diff --git a/.gn b/.gn
index 243474c50..1f94854 100644
--- a/.gn
+++ b/.gn
@@ -24,7 +24,9 @@
   "//cc/*",
 
   #"//chrome/*",  # Epic number of errors.
+  "//chrome/common/*",
   "//chrome/installer/*",
+  "//chrome/third_party/mozilla_security_manager/*",
   "//chromecast/*",
 
   # TODO(brettw): Fix http://crbug.com/460828 and uncomment the following
diff --git a/DEPS b/DEPS
index c778604b..d0491d1e 100644
--- a/DEPS
+++ b/DEPS
@@ -39,15 +39,15 @@
   # 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': 'e9759286e8eb3a0ce00923bf9462818bc67cd9f8',
+  'skia_revision': '338047e21fa321a708cd59d6f3dfdab753cf6404',
   # 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': '8ee0ef529bc0f5b171bfb92fa76051ca9a6f63b5',
+  'v8_revision': '97a062a564b09b498633305a4500a6c5a5016f93',
   # 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.
-  'swarming_revision': 'e4c0e242eeec361886ed2b89591a505ebe24db43',
+  'swarming_revision': '3db878084b52a5e4eac0a32095e490e1b6ef9526',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
@@ -67,7 +67,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '0dd93002ddf5adce17db88f1212ca2e14eba6e9c',
+  'boringssl_revision': '63fa118f3a3d065adb6ca17227bb9e407ffadccb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nss
   # and whatever else without interference from each other.
diff --git a/android_webview/browser/hardware_renderer.cc b/android_webview/browser/hardware_renderer.cc
index ff14f10..b13f0ef 100644
--- a/android_webview/browser/hardware_renderer.cc
+++ b/android_webview/browser/hardware_renderer.cc
@@ -102,10 +102,9 @@
   // during "kModeSync" stage (which does not allow GL) might result in extra
   // kModeProcess. Instead, submit the frame in "kModeDraw" stage to avoid
   // unnecessary kModeProcess.
-  scoped_ptr<ChildFrame> child_frame = child_frame_.Pass();
-  if (child_frame.get()) {
+  if (child_frame_.get() && child_frame_->frame.get()) {
     scoped_ptr<cc::CompositorFrame> child_compositor_frame =
-        child_frame->frame.Pass();
+        child_frame_->frame.Pass();
 
     // On Android we put our browser layers in physical pixels and set our
     // browser CC device_scale_factor to 1, so suppress the transform between
@@ -139,7 +138,7 @@
   // compositor might not have the tiles rasterized as the animation goes on.
   ParentCompositorDrawConstraints draw_constraints(
       draw_info->is_layer, transform, viewport.IsEmpty());
-  if (!child_frame.get() || draw_constraints.NeedUpdate(*child_frame)) {
+  if (!child_frame_.get() || draw_constraints.NeedUpdate(*child_frame_)) {
     shared_renderer_state_->PostExternalDrawConstraintsToChildCompositorOnRT(
         draw_constraints);
   }
diff --git a/android_webview/browser/hardware_renderer.h b/android_webview/browser/hardware_renderer.h
index fe7aaef..49a51ba4 100644
--- a/android_webview/browser/hardware_renderer.h
+++ b/android_webview/browser/hardware_renderer.h
@@ -61,6 +61,9 @@
   // Infromation from UI on last commit.
   gfx::Vector2d scroll_offset_;
 
+  // This holds the last ChildFrame received. Contains the frame info of the
+  // last frame. The |frame| member may be null if it's already submitted to
+  // SurfaceFactory.
   scoped_ptr<ChildFrame> child_frame_;
 
   scoped_refptr<AwGLSurface> gl_surface_;
diff --git a/ash/accelerators/accelerator_table.cc b/ash/accelerators/accelerator_table.cc
index 6f6d4b50..35888ed 100644
--- a/ash/accelerators/accelerator_table.cc
+++ b/ash/accelerators/accelerator_table.cc
@@ -264,7 +264,7 @@
     {true, ui::VKEY_W,
      ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
      DEBUG_PRINT_WINDOW_HIERARCHY},
-    {true, ui::VKEY_S,
+    {true, ui::VKEY_D,
      ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
      DEBUG_TOGGLE_DEVICE_SCALE_FACTOR},
     {true, ui::VKEY_B,
diff --git a/ash/sticky_keys/sticky_keys_overlay.cc b/ash/sticky_keys/sticky_keys_overlay.cc
index 3826f735..6c376cf 100644
--- a/ash/sticky_keys/sticky_keys_overlay.cc
+++ b/ash/sticky_keys/sticky_keys_overlay.cc
@@ -231,7 +231,16 @@
   overlay_widget_->GetNativeView()->SetName("StickyKeysOverlay");
 }
 
-StickyKeysOverlay::~StickyKeysOverlay() {}
+StickyKeysOverlay::~StickyKeysOverlay() {
+  // Remove ourself from the animator to avoid being re-entrantly called in
+  // |overlay_widget_|'s destructor.
+  ui::Layer* layer = overlay_widget_->GetLayer();
+  if (layer) {
+    ui::LayerAnimator* animator = layer->GetAnimator();
+    if (animator)
+      animator->RemoveObserver(this);
+  }
+}
 
 void StickyKeysOverlay::Show(bool visible) {
   if (is_visible_ == visible)
diff --git a/base/profiler/win32_stack_frame_unwinder.cc b/base/profiler/win32_stack_frame_unwinder.cc
index ea589bbc..2f09e8e8 100644
--- a/base/profiler/win32_stack_frame_unwinder.cc
+++ b/base/profiler/win32_stack_frame_unwinder.cc
@@ -205,7 +205,13 @@
     } else {
       // We're not at the end of the stack. This frame is untrustworthy and we
       // can't safely unwind from here.
-      if (unwind_info_present_for_all_frames_) {
+      if (!image_base) {
+        // A null image_base means that the the last unwind produced an invalid
+        // instruction pointer. This has been observed where unwind information
+        // was present for a function but was inconsistent with the actual
+        // function code, in particular in BoringSSL. See
+        // https://crbug.com/542919.
+      } else if (unwind_info_present_for_all_frames_) {
         // Unwind information was present for all previous frames, so we can
         // be confident this is case 2. Record the module to be blacklisted.
         LeafUnwindBlacklist::GetInstance()->BlacklistModule(
diff --git a/blimp/common/proto/BUILD.gn b/blimp/common/proto/BUILD.gn
index db60779..ecaa29c7 100644
--- a/blimp/common/proto/BUILD.gn
+++ b/blimp/common/proto/BUILD.gn
@@ -14,10 +14,9 @@
 proto_library("proto_lib") {
   sources = [
     "blimp_message.proto",
-    "client_control.proto",
     "common.proto",
     "compositor.proto",
+    "control.proto",
     "input.proto",
-    "server_control.proto",
   ]
 }
diff --git a/blimp/common/proto/blimp_message.proto b/blimp/common/proto/blimp_message.proto
index 9472f9ef..553119d 100644
--- a/blimp/common/proto/blimp_message.proto
+++ b/blimp/common/proto/blimp_message.proto
@@ -24,10 +24,9 @@
 
 option optimize_for = LITE_RUNTIME;
 
-import "client_control.proto";
+import "control.proto";
 import "compositor.proto";
 import "input.proto";
-import "server_control.proto";
 
 package blimp;
 
@@ -35,8 +34,7 @@
   enum Type {
     COMPOSITOR = 0;
     INPUT = 1;
-    CLIENT_CONTROL = 2;
-    SERVER_CONTROL = 3;
+    CONTROL = 2;
   }
   // Identifies the feature type of this message.
   // The feature-specific contents are contained in optional fields of the same
@@ -59,7 +57,6 @@
   // TODO(kmarshall): use a 'oneof' union when it's supported in Chromium.
   optional CompositorMessage compositor = 1000;
   optional InputMessage input = 1001;
-  optional ClientControlMessage client_control = 1002;
-  optional ServerControlMessage server_control = 1003;
+  optional ControlMessage control = 1002;
 }
 
diff --git a/blimp/common/proto/client_control.proto b/blimp/common/proto/client_control.proto
deleted file mode 100644
index 6d9f605f..0000000
--- a/blimp/common/proto/client_control.proto
+++ /dev/null
@@ -1,29 +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.
-//
-// Message definitions for client-originating browser control messages.
-//
-// Current definitions are just placeholders and are NOT final.
-// Feel free to modify this interface as necessary during feature work.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-message NavigateArgs {
-  optional string url = 1;
-}
-
-message ClientControlMessage {
-  enum Type {
-    NAVIGATE = 1;
-    STOP = 2;
-    RELOAD = 3;
-    BACK = 4;
-    FORWARD = 5;
-  }
-  optional Type type = 1;
-
-  optional NavigateArgs navigate = 1000;
-}
diff --git a/blimp/common/proto/control.proto b/blimp/common/proto/control.proto
new file mode 100644
index 0000000..fdc1c89
--- /dev/null
+++ b/blimp/common/proto/control.proto
@@ -0,0 +1,28 @@
+// 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.
+//
+// Message definitions for browser control messages.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+message LoadUrlMessage {
+  optional string url = 1;
+}
+
+message ControlMessage {
+  enum Type {
+    // Client <=> Server types.
+    CREATE_TAB = 1;
+    CLOSE_TAB = 2;
+    LOAD_URL = 3;
+
+    // Server => Client types.
+    // Client => Server types.
+  }
+  optional Type type = 1;
+
+  optional LoadUrlMessage load_url = 1000;
+}
diff --git a/blimp/common/proto/server_control.proto b/blimp/common/proto/server_control.proto
deleted file mode 100644
index f1cf976..0000000
--- a/blimp/common/proto/server_control.proto
+++ /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.
-//
-// Message definitions for server-originating browser control messages.
-//
-// Current definitions are just placeholders and are NOT final.
-// Feel free to modify this interface as necessary during feature work.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-message StatusArgs {
-  optional string url = 1;
-  optional int32 loading_progress = 2;
-  // Add error code, error message, status strings, etc.
-}
-
-message ResetSessionArgs {
-}
-
-message ErrorArgs {
-  enum ErrorCode {
-    UNKNOWN = 1;
-    UNRESPONSIVE = 2;
-    SERVER_ERROR = 3;
-  }
-
-  optional ErrorCode error_code = 1;
-  optional int32 server_error_code = 2;
-}
-
-message ServerControlMessage {
-  enum Type {
-    ERROR = 1;
-    STATUS = 2;
-  }
-  optional Type type = 1;
-
-  optional ErrorArgs error = 1000;
-  optional StatusArgs status = 1001;
-}
diff --git a/blimp/engine/browser/BUILD.gn b/blimp/engine/browser/BUILD.gn
index dc7ac4ae..43857f2c 100644
--- a/blimp/engine/browser/BUILD.gn
+++ b/blimp/engine/browser/BUILD.gn
@@ -10,18 +10,20 @@
     "blimp_browser_main_parts.h",
     "blimp_content_browser_client.cc",
     "blimp_content_browser_client.h",
+    "blimp_engine_session.cc",
+    "blimp_engine_session.h",
     "blimp_network_delegate.cc",
     "blimp_network_delegate.h",
     "blimp_permission_manager.cc",
     "blimp_permission_manager.h",
     "blimp_url_request_context_getter.cc",
     "blimp_url_request_context_getter.h",
-    "blimp_window.cc",
-    "blimp_window.h",
   ]
 
   deps = [
     "//base",
+    "//blimp/common/proto",
+    "//blimp/net:blimp_net",
     "//blimp/engine/ui",
     "//content",
     "//content/public/browser",
diff --git a/blimp/engine/browser/blimp_browser_main_parts.cc b/blimp/engine/browser/blimp_browser_main_parts.cc
index a1c0474..aaba2d3 100644
--- a/blimp/engine/browser/blimp_browser_main_parts.cc
+++ b/blimp/engine/browser/blimp_browser_main_parts.cc
@@ -4,36 +4,17 @@
 
 #include "blimp/engine/browser/blimp_browser_main_parts.h"
 
-#include "base/command_line.h"
-#include "blimp/engine/browser/blimp_window.h"
-#include "blimp/engine/ui/blimp_screen.h"
+#include "blimp/engine/browser/blimp_browser_context.h"
+#include "blimp/engine/browser/blimp_engine_session.h"
+#include "blimp/net/blimp_client_session.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/common/main_function_params.h"
 #include "net/base/net_module.h"
 #include "net/log/net_log.h"
-#include "url/gurl.h"
 
 namespace blimp {
 namespace engine {
 
-namespace {
-
-const char kDefaultURL[] = "https://www.google.com/";
-
-GURL GetStartupURL() {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  const base::CommandLine::StringVector& args = command_line->GetArgs();
-  if (args.empty())
-    return GURL(kDefaultURL);
-
-  GURL url(args[0]);
-  if (url.is_valid() && url.has_scheme())
-    return url;
-
-  return GURL(kDefaultURL);
-}
-
-}  // namespace
-
 BlimpBrowserMainParts::BlimpBrowserMainParts(
     const content::MainFunctionParams& parameters) {}
 
@@ -41,20 +22,21 @@
 
 void BlimpBrowserMainParts::PreMainMessageLoopRun() {
   net_log_.reset(new net::NetLog());
-  browser_context_.reset(new BlimpBrowserContext(false, net_log_.get()));
-  BlimpWindow::Create(browser_context_.get(), GetStartupURL(), nullptr,
-                      gfx::Size());
-}
-
-int BlimpBrowserMainParts::PreCreateThreads() {
-  screen_.reset(new BlimpScreen);
-  DCHECK(!gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE));
-  gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get());
-  return 0;
+  scoped_ptr<BlimpBrowserContext> browser_context(
+      new BlimpBrowserContext(false, net_log_.get()));
+  engine_session_.reset(new BlimpEngineSession(browser_context.Pass()));
+  engine_session_->Initialize();
+  // TODO(haibinlu): remove this after a real client session can be attached.
+  scoped_ptr<BlimpClientSession> startupSession(new BlimpClientSession);
+  engine_session_->AttachClientSession(startupSession.Pass());
 }
 
 void BlimpBrowserMainParts::PostMainMessageLoopRun() {
-  browser_context_.reset();
+  engine_session_.reset();
+}
+
+BlimpBrowserContext* BlimpBrowserMainParts::GetBrowserContext() {
+  return engine_session_->browser_context();
 }
 
 }  // namespace engine
diff --git a/blimp/engine/browser/blimp_browser_main_parts.h b/blimp/engine/browser/blimp_browser_main_parts.h
index 5c2e991a..77fd8b7 100644
--- a/blimp/engine/browser/blimp_browser_main_parts.h
+++ b/blimp/engine/browser/blimp_browser_main_parts.h
@@ -7,17 +7,21 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
-#include "blimp/engine/browser/blimp_browser_context.h"
 #include "content/public/browser/browser_main_parts.h"
 
 namespace net {
 class NetLog;
 }
 
+namespace content {
+struct MainFunctionParams;
+}
+
 namespace blimp {
 namespace engine {
 
-class BlimpScreen;
+class BlimpBrowserContext;
+class BlimpEngineSession;
 
 class BlimpBrowserMainParts : public content::BrowserMainParts {
  public:
@@ -27,14 +31,12 @@
   // content::BrowserMainParts implementation.
   void PreMainMessageLoopRun() override;
   void PostMainMessageLoopRun() override;
-  int PreCreateThreads() override;
 
-  BlimpBrowserContext* browser_context() { return browser_context_.get(); }
+  BlimpBrowserContext* GetBrowserContext();
 
  private:
   scoped_ptr<net::NetLog> net_log_;
-  scoped_ptr<BlimpBrowserContext> browser_context_;
-  scoped_ptr<BlimpScreen> screen_;
+  scoped_ptr<BlimpEngineSession> engine_session_;
 
   DISALLOW_COPY_AND_ASSIGN(BlimpBrowserMainParts);
 };
diff --git a/blimp/engine/browser/blimp_content_browser_client.cc b/blimp/engine/browser/blimp_content_browser_client.cc
index 1023fbb..6163507b 100644
--- a/blimp/engine/browser/blimp_content_browser_client.cc
+++ b/blimp/engine/browser/blimp_content_browser_client.cc
@@ -31,8 +31,8 @@
       .get();
 }
 
-BlimpBrowserContext* BlimpContentBrowserClient::browser_context() {
-  return blimp_browser_main_parts_->browser_context();
+BlimpBrowserContext* BlimpContentBrowserClient::GetBrowserContext() {
+  return blimp_browser_main_parts_->GetBrowserContext();
 }
 
 }  // namespace engine
diff --git a/blimp/engine/browser/blimp_content_browser_client.h b/blimp/engine/browser/blimp_content_browser_client.h
index aa566cdc..aee1c8c 100644
--- a/blimp/engine/browser/blimp_content_browser_client.h
+++ b/blimp/engine/browser/blimp_content_browser_client.h
@@ -27,7 +27,7 @@
       content::ProtocolHandlerMap* protocol_handlers,
       content::URLRequestInterceptorScopedVector request_interceptors) override;
 
-  BlimpBrowserContext* browser_context();
+  BlimpBrowserContext* GetBrowserContext();
 
  private:
   // Owned by BrowserMainLoop
diff --git a/blimp/engine/browser/blimp_engine_session.cc b/blimp/engine/browser/blimp_engine_session.cc
new file mode 100644
index 0000000..d75bddc67
--- /dev/null
+++ b/blimp/engine/browser/blimp_engine_session.cc
@@ -0,0 +1,166 @@
+// 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 "blimp/engine/browser/blimp_engine_session.h"
+
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/common/proto/control.pb.h"
+#include "blimp/engine/browser/blimp_browser_context.h"
+#include "blimp/engine/ui/blimp_screen.h"
+#include "blimp/net/blimp_client_session.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace blimp {
+namespace engine {
+
+BlimpEngineSession::BlimpEngineSession(
+    scoped_ptr<BlimpBrowserContext> browser_context)
+    : browser_context_(browser_context.Pass()), screen_(new BlimpScreen) {}
+
+BlimpEngineSession::~BlimpEngineSession() {}
+
+void BlimpEngineSession::Initialize() {
+  DCHECK(!gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE));
+  gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get());
+}
+
+void BlimpEngineSession::AttachClientSession(
+    scoped_ptr<BlimpClientSession> client_session) {
+  // TODO(haibinlu): auto detaches existing client session.
+  if (!client_session) {
+    NOTIMPLEMENTED();
+    return;
+  }
+
+  client_session_ = client_session.Pass();
+
+  // TODO(haibinlu): remove this once we can use client session to send in
+  // a navigation message.
+  BlimpMessage message;
+  message.set_type(BlimpMessage::CONTROL);
+  message.mutable_control()->set_type(ControlMessage::CREATE_TAB);
+  OnBlimpMessage(message);
+  message.mutable_control()->set_type(ControlMessage::LOAD_URL);
+  message.mutable_control()->mutable_load_url()->set_url(
+      "https://www.google.com/");
+  OnBlimpMessage(message);
+}
+
+void BlimpEngineSession::CreateWebContents(const int target_tab_id) {
+  if (web_contents_) {
+    // only one web_contents is supported for blimp 0.5
+    NOTIMPLEMENTED();
+    return;
+  }
+
+  content::WebContents::CreateParams create_params(browser_context_.get(),
+                                                   nullptr);
+  scoped_ptr<content::WebContents> new_contents =
+      make_scoped_ptr(content::WebContents::Create(create_params));
+  PlatformSetContents(new_contents.Pass());
+}
+
+void BlimpEngineSession::LoadUrl(const int target_tab_id, const GURL& url) {
+  if (url.is_empty() || !web_contents_)
+    return;
+
+  content::NavigationController::LoadURLParams params(url);
+  params.transition_type = ui::PageTransitionFromInt(
+      ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
+  web_contents_->GetController().LoadURLWithParams(params);
+  web_contents_->Focus();
+}
+
+net::Error BlimpEngineSession::OnBlimpMessage(const BlimpMessage& message) {
+  DCHECK(message.type() == BlimpMessage::CONTROL);
+
+  switch (message.control().type()) {
+    case ControlMessage::CREATE_TAB:
+      CreateWebContents(message.target_tab_id());
+      break;
+    case ControlMessage::LOAD_URL:
+      LoadUrl(message.target_tab_id(),
+              GURL(message.control().load_url().url()));
+      break;
+    default:
+      NOTIMPLEMENTED();
+  }
+
+  return net::OK;
+}
+
+void BlimpEngineSession::AddNewContents(content::WebContents* source,
+                                        content::WebContents* new_contents,
+                                        WindowOpenDisposition disposition,
+                                        const gfx::Rect& initial_rect,
+                                        bool user_gesture,
+                                        bool* was_blocked) {
+  NOTIMPLEMENTED();
+}
+
+content::WebContents* BlimpEngineSession::OpenURLFromTab(
+    content::WebContents* source,
+    const content::OpenURLParams& params) {
+  // CURRENT_TAB is the only one we implement for now.
+  if (params.disposition != CURRENT_TAB) {
+    // TODO(haibinlu): handle other disposition properly.
+    NOTIMPLEMENTED();
+    return nullptr;
+  }
+  // TOOD(haibinlu): add helper method to get LoadURLParams from OpenURLParams.
+  content::NavigationController::LoadURLParams load_url_params(params.url);
+  load_url_params.source_site_instance = params.source_site_instance;
+  load_url_params.referrer = params.referrer;
+  load_url_params.frame_tree_node_id = params.frame_tree_node_id;
+  load_url_params.transition_type = params.transition;
+  load_url_params.extra_headers = params.extra_headers;
+  load_url_params.should_replace_current_entry =
+      params.should_replace_current_entry;
+
+  if (params.transferred_global_request_id != content::GlobalRequestID()) {
+    // The navigation as being transferred from one RVH to another.
+    // Copies the request ID of the old request.
+    load_url_params.is_renderer_initiated = params.is_renderer_initiated;
+    load_url_params.transferred_global_request_id =
+        params.transferred_global_request_id;
+  } else if (params.is_renderer_initiated) {
+    load_url_params.is_renderer_initiated = true;
+  }
+
+  source->GetController().LoadURLWithParams(load_url_params);
+  return source;
+}
+
+void BlimpEngineSession::RequestToLockMouse(content::WebContents* web_contents,
+                                            bool user_gesture,
+                                            bool last_unlocked_by_target) {
+  web_contents->GotResponseToLockMouseRequest(true);
+}
+
+void BlimpEngineSession::CloseContents(content::WebContents* source) {
+  if (source == web_contents_)
+    web_contents_.reset();
+}
+
+void BlimpEngineSession::ActivateContents(content::WebContents* contents) {
+  contents->GetRenderViewHost()->GetWidget()->Focus();
+}
+
+void BlimpEngineSession::DeactivateContents(content::WebContents* contents) {
+  contents->GetRenderViewHost()->GetWidget()->Blur();
+}
+
+void BlimpEngineSession::PlatformSetContents(
+    scoped_ptr<content::WebContents> new_contents) {
+  new_contents->SetDelegate(this);
+  web_contents_ = new_contents.Pass();
+}
+
+}  // namespace engine
+}  // namespace blimp
diff --git a/blimp/engine/browser/blimp_engine_session.h b/blimp/engine/browser/blimp_engine_session.h
new file mode 100644
index 0000000..c161867
--- /dev/null
+++ b/blimp/engine/browser/blimp_engine_session.h
@@ -0,0 +1,85 @@
+// 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 BLIMP_ENGINE_BROWSER_BLIMP_ENGINE_SESSION_H_
+#define BLIMP_ENGINE_BROWSER_BLIMP_ENGINE_SESSION_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "blimp/net/blimp_message_receiver.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+class BrowserContext;
+class WebContents;
+}
+
+namespace blimp {
+
+class BlimpClientSession;
+class BlimpMessage;
+
+namespace engine {
+
+class BlimpBrowserContext;
+class BlimpScreen;
+
+class BlimpEngineSession : public BlimpMessageReceiver,
+                           public content::WebContentsDelegate {
+ public:
+  explicit BlimpEngineSession(scoped_ptr<BlimpBrowserContext> browser_context);
+  ~BlimpEngineSession() override;
+
+  void Initialize();
+
+  BlimpBrowserContext* browser_context() { return browser_context_.get(); }
+
+  void AttachClientSession(scoped_ptr<BlimpClientSession> client_session);
+
+ private:
+  // Creates a new WebContents, which will be indexed by |target_tab_id|.
+  void CreateWebContents(const int target_tab_id);
+
+  // Navigates the target tab to the |url|.
+  void LoadUrl(const int target_tab_id, const GURL& url);
+
+  // BlimpMessageReceiver implementation.
+  net::Error OnBlimpMessage(const BlimpMessage& message) override;
+
+  // content::WebContentsDelegate implementation.
+  content::WebContents* OpenURLFromTab(
+      content::WebContents* source,
+      const content::OpenURLParams& params) override;
+  void AddNewContents(content::WebContents* source,
+                      content::WebContents* new_contents,
+                      WindowOpenDisposition disposition,
+                      const gfx::Rect& initial_rect,
+                      bool user_gesture,
+                      bool* was_blocked) override;
+  void RequestToLockMouse(content::WebContents* web_contents,
+                          bool user_gesture,
+                          bool last_unlocked_by_target) override;
+  void CloseContents(content::WebContents* source) override;
+  void ActivateContents(content::WebContents* contents) override;
+  void DeactivateContents(content::WebContents* contents) override;
+
+  // Sets up and owns |new_contents|.
+  void PlatformSetContents(scoped_ptr<content::WebContents> new_contents);
+
+  scoped_ptr<BlimpBrowserContext> browser_context_;
+  scoped_ptr<BlimpScreen> screen_;
+
+  // Only one web_contents is supported for blimp 0.5
+  scoped_ptr<content::WebContents> web_contents_;
+
+  // Currently attached client session.
+  scoped_ptr<BlimpClientSession> client_session_;
+  DISALLOW_COPY_AND_ASSIGN(BlimpEngineSession);
+};
+
+}  // namespace engine
+}  // namespace blimp
+
+#endif  // BLIMP_ENGINE_BROWSER_BLIMP_ENGINE_SESSION_H_
diff --git a/blimp/engine/browser/blimp_url_request_context_getter.cc b/blimp/engine/browser/blimp_url_request_context_getter.cc
index e49c5f2..f2bc1dec 100644
--- a/blimp/engine/browser/blimp_url_request_context_getter.cc
+++ b/blimp/engine/browser/blimp_url_request_context_getter.cc
@@ -180,10 +180,10 @@
     network_session_params.host_resolver =
         url_request_context_->host_resolver();
 
-    storage_->set_http_transaction_factory(
-        make_scoped_ptr(
-            new net::HttpCache(network_session_params, main_backend))
-            .Pass());
+    storage_->set_http_network_session(
+        make_scoped_ptr(new net::HttpNetworkSession(network_session_params)));
+    storage_->set_http_transaction_factory(make_scoped_ptr(new net::HttpCache(
+        storage_->http_network_session(), main_backend, true)));
 
     scoped_ptr<net::URLRequestJobFactoryImpl> job_factory(
         new net::URLRequestJobFactoryImpl());
diff --git a/blimp/engine/browser/blimp_window.cc b/blimp/engine/browser/blimp_window.cc
deleted file mode 100644
index bc79448..0000000
--- a/blimp/engine/browser/blimp_window.cc
+++ /dev/null
@@ -1,140 +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 "blimp/engine/browser/blimp_window.h"
-
-#include "base/strings/string_util.h"
-#include "blimp/engine/browser/blimp_browser_main_parts.h"
-#include "blimp/engine/browser/blimp_content_browser_client.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/web_contents.h"
-
-namespace blimp {
-namespace engine {
-
-namespace {
-const int kDefaultWindowWidthDip = 1;
-const int kDefaultWindowHeightDip = 1;
-
-// TODO(haibinlu): cleanup BlimpWindows on shutdown. See crbug/540498.
-typedef std::vector<BlimpWindow*> BlimpWindows;
-base::LazyInstance<BlimpWindows>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
-
-// Returns the default size if |size| has 0 for width and/or height;
-// otherwise, returns |size|.
-gfx::Size AdjustWindowSize(const gfx::Size& size) {
-  return size.IsEmpty()
-             ? gfx::Size(kDefaultWindowWidthDip, kDefaultWindowHeightDip)
-             : size;
-}
-}  // namespace
-
-BlimpWindow::~BlimpWindow() {
-  BlimpWindows* instances = g_instances.Pointer();
-  BlimpWindows::iterator it(
-      std::find(instances->begin(), instances->end(), this));
-  DCHECK(it != instances->end());
-  instances->erase(it);
-}
-
-// static
-void BlimpWindow::Create(content::BrowserContext* browser_context,
-                         const GURL& url,
-                         content::SiteInstance* site_instance,
-                         const gfx::Size& initial_size) {
-  content::WebContents::CreateParams create_params(browser_context,
-                                                   site_instance);
-  scoped_ptr<content::WebContents> web_contents(
-      content::WebContents::Create(create_params));
-  BlimpWindow* win = DoCreate(web_contents.Pass(), initial_size);
-  if (!url.is_empty())
-    win->LoadURL(url);
-}
-
-void BlimpWindow::LoadURL(const GURL& url) {
-  content::NavigationController::LoadURLParams params(url);
-  params.transition_type = ui::PageTransitionFromInt(
-      ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
-  web_contents_->GetController().LoadURLWithParams(params);
-  web_contents_->Focus();
-}
-
-void BlimpWindow::AddNewContents(content::WebContents* source,
-                                 content::WebContents* new_contents,
-                                 WindowOpenDisposition disposition,
-                                 const gfx::Rect& initial_rect,
-                                 bool user_gesture,
-                                 bool* was_blocked) {
-  DoCreate(scoped_ptr<content::WebContents>(new_contents), initial_rect.size());
-}
-
-content::WebContents* BlimpWindow::OpenURLFromTab(
-    content::WebContents* source,
-    const content::OpenURLParams& params) {
-  // CURRENT_TAB is the only one we implement for now.
-  if (params.disposition != CURRENT_TAB)
-    return nullptr;
-  // TOOD(haibinlu): add helper method to get LoadURLParams from OpenURLParams.
-  content::NavigationController::LoadURLParams load_url_params(params.url);
-  load_url_params.source_site_instance = params.source_site_instance;
-  load_url_params.referrer = params.referrer;
-  load_url_params.frame_tree_node_id = params.frame_tree_node_id;
-  load_url_params.transition_type = params.transition;
-  load_url_params.extra_headers = params.extra_headers;
-  load_url_params.should_replace_current_entry =
-      params.should_replace_current_entry;
-
-  if (params.transferred_global_request_id != content::GlobalRequestID()) {
-    load_url_params.is_renderer_initiated = params.is_renderer_initiated;
-    load_url_params.transferred_global_request_id =
-        params.transferred_global_request_id;
-  } else if (params.is_renderer_initiated) {
-    load_url_params.is_renderer_initiated = true;
-  }
-
-  source->GetController().LoadURLWithParams(load_url_params);
-  return source;
-}
-
-void BlimpWindow::RequestToLockMouse(content::WebContents* web_contents,
-                                     bool user_gesture,
-                                     bool last_unlocked_by_target) {
-  web_contents->GotResponseToLockMouseRequest(true);
-}
-
-void BlimpWindow::CloseContents(content::WebContents* source) {
-  delete this;
-}
-
-void BlimpWindow::ActivateContents(content::WebContents* contents) {
-  contents->GetRenderViewHost()->Focus();
-}
-
-void BlimpWindow::DeactivateContents(content::WebContents* contents) {
-  contents->GetRenderViewHost()->Blur();
-}
-
-BlimpWindow::BlimpWindow(scoped_ptr<content::WebContents> web_contents)
-    : web_contents_(web_contents.Pass()) {
-  web_contents_->SetDelegate(this);
-  g_instances.Get().push_back(this);
-}
-
-// static
-BlimpWindow* BlimpWindow::DoCreate(
-    scoped_ptr<content::WebContents> web_contents,
-    const gfx::Size& initial_size) {
-  BlimpWindow* win = new BlimpWindow(web_contents.Pass());
-  content::RenderWidgetHostView* host_view =
-      win->web_contents_->GetRenderWidgetHostView();
-  if (host_view)
-    host_view->SetSize(AdjustWindowSize(initial_size));
-  return win;
-}
-
-}  // namespace engine
-}  // namespace blimp
diff --git a/blimp/engine/browser/blimp_window.h b/blimp/engine/browser/blimp_window.h
deleted file mode 100644
index fadf3b63..0000000
--- a/blimp/engine/browser/blimp_window.h
+++ /dev/null
@@ -1,79 +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 BLIMP_ENGINE_BROWSER_BLIMP_WINDOW_H_
-#define BLIMP_ENGINE_BROWSER_BLIMP_WINDOW_H_
-
-#include <vector>
-
-#include "base/lazy_instance.h"
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/web_contents_delegate.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace content {
-class BrowserContext;
-class SiteInstance;
-class WebContents;
-}
-
-class GURL;
-
-namespace blimp {
-namespace engine {
-
-// Owns and controls a WebContents instance corresponding to a window on
-// Blimp client.
-class BlimpWindow : public content::WebContentsDelegate {
- public:
-  // This also unregisters itself with a singleton registry.
-  ~BlimpWindow() override;
-
-  // Creates a new blimp window with |initial_size| and navigates to the |url|.
-  // Caller retains ownership of |browser_context| and |site_instance| and
-  // ensures |browser_context| and |site_instance| outlives BlimpWindow.
-  static void Create(content::BrowserContext* browser_context,
-                     const GURL& url,
-                     content::SiteInstance* site_instance,
-                     const gfx::Size& initial_size);
-
-  // Navigates to |url|.
-  void LoadURL(const GURL& url);
-
-  // content::WebContentsDelegate implementation.
-  content::WebContents* OpenURLFromTab(
-      content::WebContents* source,
-      const content::OpenURLParams& params) override;
-  void AddNewContents(content::WebContents* source,
-                      content::WebContents* new_contents,
-                      WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_rect,
-                      bool user_gesture,
-                      bool* was_blocked) override;
-  void RequestToLockMouse(content::WebContents* web_contents,
-                          bool user_gesture,
-                          bool last_unlocked_by_target) override;
-  void CloseContents(content::WebContents* source) override;
-  void ActivateContents(content::WebContents* contents) override;
-  void DeactivateContents(content::WebContents* contents) override;
-
- private:
-  // The newly created instance registers itself with a singleton registry.
-  explicit BlimpWindow(scoped_ptr<content::WebContents> web_contents);
-
-  // Helper to create a new BlimpWindow given |web_contents|.
-  // The newly window is owned by a singleton registry.
-  static BlimpWindow* DoCreate(scoped_ptr<content::WebContents> web_contents,
-                               const gfx::Size& initial_size);
-
-  scoped_ptr<content::WebContents> web_contents_;
-
-  DISALLOW_COPY_AND_ASSIGN(BlimpWindow);
-};
-
-}  // namespace engine
-}  // namespace blimp
-
-#endif  // BLIMP_ENGINE_BROWSER_BLIMP_WINDOW_H_
diff --git a/blimp/engine/ui/blimp_screen.cc b/blimp/engine/ui/blimp_screen.cc
index 2eba20f3..02829679 100644
--- a/blimp/engine/ui/blimp_screen.cc
+++ b/blimp/engine/ui/blimp_screen.cc
@@ -10,13 +10,14 @@
 namespace {
 
 const int64 kDisplayId = 1;
-const int kDefaultDisplayWidth = 1;
-const int kDefaultDisplayHeight = 1;
 const float kDefaultScale = 1.0f;
 const int kNumDisplays = 1;
 
 }  // namespace
 
+const int BlimpScreen::kDefaultDisplayWidth = 800;
+const int BlimpScreen::kDefaultDisplayHeight = 600;
+
 BlimpScreen::BlimpScreen() : display_(kDisplayId) {
   display_.SetScaleAndBounds(
       kDefaultScale, gfx::Rect(kDefaultDisplayWidth, kDefaultDisplayHeight));
diff --git a/blimp/engine/ui/blimp_screen.h b/blimp/engine/ui/blimp_screen.h
index 99858b8a..499e3285d 100644
--- a/blimp/engine/ui/blimp_screen.h
+++ b/blimp/engine/ui/blimp_screen.h
@@ -35,6 +35,9 @@
   void AddObserver(gfx::DisplayObserver* observer) override;
   void RemoveObserver(gfx::DisplayObserver* observer) override;
 
+  static const int kDefaultDisplayWidth;
+  static const int kDefaultDisplayHeight;
+
  private:
   gfx::Display display_;
 
diff --git a/blimp/net/BUILD.gn b/blimp/net/BUILD.gn
index 5a1784c..05a1ff3 100644
--- a/blimp/net/BUILD.gn
+++ b/blimp/net/BUILD.gn
@@ -6,6 +6,8 @@
 
 component("blimp_net") {
   sources = [
+    "blimp_client_session.cc",
+    "blimp_client_session.h",
     "blimp_message_dispatcher.cc",
     "blimp_message_dispatcher.h",
     "blimp_message_receiver.h",
diff --git a/blimp/net/blimp_client_session.cc b/blimp/net/blimp_client_session.cc
new file mode 100644
index 0000000..c412be22
--- /dev/null
+++ b/blimp/net/blimp_client_session.cc
@@ -0,0 +1,13 @@
+// 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 "blimp/net/blimp_client_session.h"
+
+namespace blimp {
+
+BlimpClientSession::BlimpClientSession() {}
+
+BlimpClientSession::~BlimpClientSession() {}
+
+}  // namespace blimp
diff --git a/blimp/net/blimp_client_session.h b/blimp/net/blimp_client_session.h
new file mode 100644
index 0000000..7cde1537
--- /dev/null
+++ b/blimp/net/blimp_client_session.h
@@ -0,0 +1,23 @@
+// 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 BLIMP_NET_BLIMP_CLIENT_SESSION_H_
+#define BLIMP_NET_BLIMP_CLIENT_SESSION_H_
+
+#include "base/macros.h"
+
+namespace blimp {
+
+class BlimpClientSession {
+ public:
+  BlimpClientSession();
+  ~BlimpClientSession();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BlimpClientSession);
+};
+
+}  // namespace blimp
+
+#endif  // BLIMP_NET_BLIMP_CLIENT_SESSION_H_
diff --git a/build/android/copy_ex.gypi b/build/android/copy_ex.gypi
index 8c49d24..bae0dd24 100644
--- a/build/android/copy_ex.gypi
+++ b/build/android/copy_ex.gypi
@@ -6,11 +6,9 @@
 #
 # Variables:
 #   dest_path - directory to copy files to.
-#   src_files - optional, a list of files to copy without changing name.
+#   src_files - a list of files to copy.
 #   clear - optional, if set, clear directory before copying files.
-#   renaming_sources - optional, a list of files to copy and rename.
-#   renaming_destinations - optional, a list of new file names corresponding to
-#                           renaming_sources.
+#   stamp - optional, path to touch on success.
 #
 # Exmaple
 #  {
@@ -20,10 +18,6 @@
 #      'dest_path': 'apk/assets/path',
 #      'src_files': ['path1/fr.pak'],
 #      'clear': 1,
-#      # path2/old1 and path3/old2 will be copied to apk/assets/path and
-#      # renamed to new1, new2 respectly.
-#      'renaming_sources': ['path2/old1', 'path3/old2'],
-#      'renaming_destinations': ['new1', 'new2'],
 #    },
 #    'includes': [ '../build/android/copy_ex.gypi' ],
 #  },
@@ -31,49 +25,35 @@
 {
   'variables': {
     'clear%': 0,
-    'src_files%': [],
-    'renaming_sources%': [],
-    'renaming_destinations%': [],
+    'stamp%': '',
   },
   'actions': [{
     'action_name': '<(_target_name)_copy_ex',
     'variables': {
       'additional_args':[],
-      'local_inputs': [],
-      'dest_files': [],
       'conditions': [
         ['clear == 1', {
           'additional_args': ['--clear'],
         }],
-        ['src_files != []', {
-          'additional_args': ['--files', '<(src_files)'],
-          'local_inputs': ['<@(src_files)'],
-          # src_files will be used to generate destination files path for
-          # outputs.
-          'dest_files': ['<@(src_files)'],
-        }],
-        ['renaming_sources != []', {
-          'additional_args': [
-            '--renaming-sources', '<(renaming_sources)',
-            '--renaming-destinations', '<(renaming_destinations)'
-          ],
-          'local_inputs': ['<@(renaming_sources)'],
-          'dest_files': ['<@(renaming_destinations)'],
+        ['stamp != ""', {
+          'additional_args': ['--stamp', '<(stamp)'],
         }],
       ],
     },
     'inputs': [
       '<(DEPTH)/build/android/gyp/copy_ex.py',
       '<(DEPTH)/build/android/gyp/generate_copy_ex_outputs.py',
-      '<@(local_inputs)',
+      '<@(src_files)',
     ],
     'outputs': [
-      '<!@pymod_do_main(generate_copy_ex_outputs --dest-path <(dest_path) --src-files <(dest_files))',
+      '<(stamp)',
+      '<!@pymod_do_main(generate_copy_ex_outputs --dest-path <(dest_path) --src-files <(src_files))'
     ],
     'action': [
       'python', '<(DEPTH)/build/android/gyp/copy_ex.py',
       '--dest', '<(dest_path)',
-      '<@(additional_args)',
+      '--files', '<(src_files)',
+      '<(additional_args)',
     ],
   }],
 }
diff --git a/build/android/gyp/copy_ex.py b/build/android/gyp/copy_ex.py
index f99e71d..a474e770 100755
--- a/build/android/gyp/copy_ex.py
+++ b/build/android/gyp/copy_ex.py
@@ -6,7 +6,6 @@
 
 """Copies files to a directory."""
 
-import itertools
 import optparse
 import os
 import shutil
@@ -24,49 +23,6 @@
     result.extend([os.path.join(root[len(dirname):], f) for f in files])
   return result
 
-def CopyFile(f, dest, deps):
-  """Copy file or directory and update deps."""
-  if os.path.isdir(f):
-    shutil.copytree(f, os.path.join(dest, os.path.basename(f)))
-    deps.extend(_get_all_files(f))
-  else:
-    shutil.copy(f, dest)
-    deps.append(f)
-
-def DoCopy(options, deps):
-  """Copy files or directories given in options.files and update deps."""
-  files = list(itertools.chain.from_iterable(build_utils.ParseGypList(f)
-                                             for f in options.files))
-
-  for f in files:
-    if os.path.isdir(f):
-      if not options.clear:
-        print ('To avoid stale files you must use --clear when copying '
-               'directories')
-        sys.exit(-1)
-    else:
-      CopyFile(f, options.dest, deps)
-
-def DoRenaming(options, deps):
-  """Copy and rename files given in options.renaming_sources and update deps."""
-  src_files = list(itertools.chain.from_iterable(
-                   build_utils.ParseGypList(f)
-                   for f in options.renaming_sources))
-
-  dest_files = list(itertools.chain.from_iterable(
-                    build_utils.ParseGypList(f)
-                    for f in options.renaming_destinations))
-
-  if (len(src_files) != len(dest_files)):
-    print('Renaming source and destination files not match.')
-    sys.exit(-1)
-
-  for src, dest in itertools.izip(src_files, dest_files):
-    if os.path.isdir(src):
-      print ('renaming diretory is not supported.')
-      sys.exit(-1)
-    else:
-      CopyFile(src, os.path.join(options.dest, dest), deps)
 
 def main(args):
   args = build_utils.ExpandFileArgs(args)
@@ -82,14 +38,6 @@
                     'before copying files to it. This is highly recommended to '
                     'ensure that no stale files are left in the directory.')
   parser.add_option('--stamp', help='Path to touch on success.')
-  parser.add_option('--renaming-sources',
-                    action='append',
-                    help='List of files need to be renamed while being '
-                         'copied to dest directory')
-  parser.add_option('--renaming-destinations',
-                    action='append',
-                    help='List of destination file name without path, the '
-                         'number of elements must match rename-sources.')
 
   options, _ = parser.parse_args(args)
 
@@ -97,13 +45,23 @@
     build_utils.DeleteDirectory(options.dest)
     build_utils.MakeDirectory(options.dest)
 
+  files = []
+  for file_arg in options.files:
+    files += build_utils.ParseGypList(file_arg)
+
   deps = []
 
-  if options.files:
-    DoCopy(options, deps)
-
-  if options.renaming_sources:
-    DoRenaming(options, deps)
+  for f in files:
+    if os.path.isdir(f):
+      if not options.clear:
+        print ('To avoid stale files you must use --clear when copying '
+               'directories')
+        sys.exit(-1)
+      shutil.copytree(f, os.path.join(options.dest, os.path.basename(f)))
+      deps.extend(_get_all_files(f))
+    else:
+      shutil.copy(f, options.dest)
+      deps.append(f)
 
   if options.depfile:
     build_utils.WriteDepfile(
diff --git a/build/android/incremental_install/BUILD.gn b/build/android/incremental_install/BUILD.gn
index 1b54701..ab39e4c2 100644
--- a/build/android/incremental_install/BUILD.gn
+++ b/build/android/incremental_install/BUILD.gn
@@ -9,6 +9,7 @@
   dex_path = "$target_gen_dir/bootstrap.dex"
   java_files = [
     "java/org/chromium/incrementalinstall/BootstrapApplication.java",
+    "java/org/chromium/incrementalinstall/BootstrapInstrumentation.java",
     "java/org/chromium/incrementalinstall/ClassLoaderPatcher.java",
     "java/org/chromium/incrementalinstall/LockFile.java",
     "java/org/chromium/incrementalinstall/Reflect.java",
diff --git a/build/android/incremental_install/__init__.py b/build/android/incremental_install/__init__.py
new file mode 100644
index 0000000..1aaf0e1
--- /dev/null
+++ b/build/android/incremental_install/__init__.py
@@ -0,0 +1,4 @@
+# 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.
+
diff --git a/build/android/incremental_install/create_install_script.py b/build/android/incremental_install/create_install_script.py
index 614cbb7..5040a565 100755
--- a/build/android/incremental_install/create_install_script.py
+++ b/build/android/incremental_install/create_install_script.py
@@ -28,20 +28,40 @@
 import subprocess
 import sys
 
-def main():
+
+def _ResolvePath(path):
   script_directory = os.path.dirname(__file__)
+  return os.path.abspath(os.path.join(script_directory, path))
 
-  def resolve_path(path):
-    return os.path.abspath(os.path.join(script_directory, path))
 
-  cmd_path = resolve_path({cmd_path})
-  cmd_args = [cmd_path] + {cmd_args}
-  cmd_path_args = {cmd_path_args}
-  for arg, path in cmd_path_args:
-    if arg:
-      cmd_args.append(arg)
-    cmd_args.append(resolve_path(path))
+# Exported to allow test runner to be able to install incremental apks.
+def GetInstallParameters():
+  apk_path = {apk_path}
+  lib_dir = {lib_dir}
+  dex_files = {dex_files}
+  splits = {splits}
 
+  return dict(apk_path=_ResolvePath(apk_path),
+              dex_files=[_ResolvePath(p) for p in dex_files],
+              lib_dir=_ResolvePath(lib_dir),
+              splits=[_ResolvePath(p) for p in splits])
+
+
+def main():
+  output_directory = {output_directory}
+  cmd_path = {cmd_path}
+  params = GetInstallParameters()
+  cmd_args = [
+      _ResolvePath(cmd_path),
+      '--output-directory', _ResolvePath(output_directory),
+  ]
+  if params['lib_dir']:
+    cmd_args.extend(('--lib-dir', params['lib_dir']))
+  for dex_path in params['dex_files']:
+    cmd_args.extend(('--dex-file', dex_path))
+  for split in params['splits']:
+    cmd_args.extend(('--split', split))
+  cmd_args.append(params['apk_path'])
   return subprocess.call(cmd_args + sys.argv[1:])
 
 if __name__ == '__main__':
@@ -87,32 +107,23 @@
   options = _ParseArgs(args)
 
   def relativize(path):
-    return os.path.relpath(path, os.path.dirname(options.script_output_path))
+    script_dir = os.path.dirname(options.script_output_path)
+    return path and os.path.relpath(path, script_dir)
 
   installer_path = os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'android',
                                 'incremental_install', 'installer.py')
-  installer_path = relativize(installer_path)
-
-  path_args = [
-      ('--output-directory', relativize(options.output_directory)),
-      (None, relativize(options.apk_path)),
-  ]
-
-  if options.lib_dir:
-    path_args.append(('--lib-dir', relativize(options.lib_dir)))
-
-  if options.dex_files:
-    for dex_file in options.dex_files:
-      path_args.append(('--dex-file', relativize(dex_file)))
-
-  for split_arg in options.splits:
-    path_args.append(('--split', relativize(split_arg)))
+  pformat = pprint.pformat
+  template_args = {
+      'cmd_path': pformat(relativize(installer_path)),
+      'apk_path': pformat(relativize(options.apk_path)),
+      'output_directory': pformat(relativize(options.output_directory)),
+      'lib_dir': pformat(relativize(options.lib_dir)),
+      'dex_files': pformat([relativize(p) for p in options.dex_files]),
+      'splits': pformat([relativize(p) for p in options.splits]),
+  }
 
   with open(options.script_output_path, 'w') as script:
-    script.write(SCRIPT_TEMPLATE.format(
-        cmd_path=pprint.pformat(installer_path),
-        cmd_args='[]',
-        cmd_path_args=pprint.pformat(path_args)))
+    script.write(SCRIPT_TEMPLATE.format(**template_args))
 
   os.chmod(options.script_output_path, 0750)
 
diff --git a/build/android/incremental_install/generate_android_manifest.py b/build/android/incremental_install/generate_android_manifest.py
index 17eabd4d..163b4c3 100755
--- a/build/android/incremental_install/generate_android_manifest.py
+++ b/build/android/incremental_install/generate_android_manifest.py
@@ -21,8 +21,10 @@
 ElementTree.register_namespace('android', _ANDROID_NAMESPACE)
 
 _INCREMENTAL_APP_NAME = 'org.chromium.incrementalinstall.BootstrapApplication'
-_META_DATA_NAME = 'incremental-install-real-app'
+_META_DATA_APP_NAME = 'incremental-install-real-app'
+_META_DATA_INSTRUMENTATION_NAME = 'incremental-install-real-instrumentation'
 _DEFAULT_APPLICATION_CLASS = 'android.app.Application'
+_DEFAULT_INSTRUMENTATION_CLASS = 'android.app.Instrumentation'
 
 
 def _AddNamespace(name):
@@ -45,6 +47,12 @@
   return parser.parse_args()
 
 
+def _CreateMetaData(parent, name, value):
+  meta_data_node = ElementTree.SubElement(parent, 'meta-data')
+  meta_data_node.set(_AddNamespace('name'), name)
+  meta_data_node.set(_AddNamespace('value'), value)
+
+
 def _ProcessManifest(main_manifest, disable_isolated_processes):
   """Returns a transformed AndroidManifest.xml for use with _incremental apks.
 
@@ -68,10 +76,18 @@
   real_app_class = app_node.get(_AddNamespace('name'),
                                 _DEFAULT_APPLICATION_CLASS)
   app_node.set(_AddNamespace('name'), _INCREMENTAL_APP_NAME)
+  _CreateMetaData(app_node, _META_DATA_APP_NAME, real_app_class)
 
-  meta_data_node = ElementTree.SubElement(app_node, 'meta-data')
-  meta_data_node.set(_AddNamespace('name'), _META_DATA_NAME)
-  meta_data_node.set(_AddNamespace('value'), real_app_class)
+  # Seems to be a bug in ElementTree, as doc.find() doesn't work here.
+  instrumentation_nodes = doc.findall('instrumentation')
+  if instrumentation_nodes:
+    instrumentation_node = instrumentation_nodes[0]
+    real_instrumentation_class = instrumentation_node.get(_AddNamespace('name'))
+    instrumentation_node.set(_AddNamespace('name'),
+                             _DEFAULT_INSTRUMENTATION_CLASS)
+    _CreateMetaData(app_node, _META_DATA_INSTRUMENTATION_NAME,
+                    real_instrumentation_class)
+
   return ElementTree.tostring(doc, encoding='UTF-8')
 
 
diff --git a/build/android/incremental_install/installer.py b/build/android/incremental_install/installer.py
index 40d2d7b6..b5ed5ce 100755
--- a/build/android/incremental_install/installer.py
+++ b/build/android/incremental_install/installer.py
@@ -24,8 +24,10 @@
 from pylib.utils import run_tests_helper
 from pylib.utils import time_profile
 
-sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'gyp'))
+prev_sys_path = list(sys.path)
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir, 'gyp'))
 from util import build_utils
+sys.path = prev_sys_path
 
 
 def _TransformDexPaths(paths):
@@ -46,6 +48,142 @@
   return timer
 
 
+def _GetDeviceIncrementalDir(package):
+  """Returns the device path to put incremental files for the given package."""
+  return '/data/local/tmp/incremental-app-%s' % package
+
+
+def Uninstall(device, package):
+  """Uninstalls and removes all incremental files for the given package."""
+  main_timer = time_profile.TimeProfile()
+  device.Uninstall(package)
+  device.RunShellCommand(['rm', '-rf', _GetDeviceIncrementalDir(package)],
+                         check_return=True)
+  logging.info('Uninstall took %s seconds.', main_timer.GetDelta())
+
+
+def Install(device, apk, split_globs=None, lib_dir=None, dex_files=None,
+            enable_device_cache=True, use_concurrency=True):
+  """Installs the given incremental apk and all required supporting files.
+
+  Args:
+    device: A DeviceUtils instance.
+    apk: The path to the apk, or an ApkHelper instance.
+    split_globs: Glob patterns for any required apk splits (optional).
+    lib_dir: Directory containing the app's native libraries (optional).
+    dex_files: List of .dex.jar files that comprise the app's Dalvik code.
+    enable_device_cache: Whether to enable on-device caching of checksums.
+    use_concurrency: Whether to speed things up using multiple threads.
+  """
+  main_timer = time_profile.TimeProfile()
+  install_timer = time_profile.TimeProfile()
+  push_native_timer = time_profile.TimeProfile()
+  push_dex_timer = time_profile.TimeProfile()
+
+  apk = apk_helper.ToHelper(apk)
+  apk_package = apk.GetPackageName()
+  device_incremental_dir = _GetDeviceIncrementalDir(apk_package)
+
+  # Install .apk(s) if any of them have changed.
+  def do_install():
+    install_timer.Start()
+    if split_globs:
+      splits = []
+      for split_glob in split_globs:
+        splits.extend((f for f in glob.glob(split_glob)))
+      device.InstallSplitApk(apk, splits, reinstall=True,
+                             allow_cached_props=True, permissions=())
+    else:
+      device.Install(apk, reinstall=True, permissions=())
+    install_timer.Stop(log=False)
+
+  # Push .so and .dex files to the device (if they have changed).
+  def do_push_files():
+    if lib_dir:
+      push_native_timer.Start()
+      device_lib_dir = posixpath.join(device_incremental_dir, 'lib')
+      device.PushChangedFiles([(lib_dir, device_lib_dir)],
+                              delete_device_stale=True)
+      push_native_timer.Stop(log=False)
+
+    if dex_files:
+      push_dex_timer.Start()
+      # Put all .dex files to be pushed into a temporary directory so that we
+      # can use delete_device_stale=True.
+      with build_utils.TempDir() as temp_dir:
+        device_dex_dir = posixpath.join(device_incremental_dir, 'dex')
+        # Ensure no two files have the same name.
+        transformed_names = _TransformDexPaths(dex_files)
+        for src_path, dest_name in zip(dex_files, transformed_names):
+          shutil.copyfile(src_path, os.path.join(temp_dir, dest_name))
+        device.PushChangedFiles([(temp_dir, device_dex_dir)],
+                                delete_device_stale=True)
+      push_dex_timer.Stop(log=False)
+
+  def check_selinux():
+    # Samsung started using SELinux before Marshmallow. There may be even more
+    # cases where this is required...
+    has_selinux = (device.build_version_sdk >= version_codes.MARSHMALLOW or
+                   device.GetProp('selinux.policy_version'))
+    if has_selinux and apk.HasIsolatedProcesses():
+      raise Exception('Cannot use incremental installs on versions of Android '
+                      'where isoloated processes cannot access the filesystem '
+                      '(this includes Android M+, and Samsung L+) without '
+                      'first disabling isoloated processes.\n'
+                      'To do so, use GN arg:\n'
+                      '    disable_incremental_isolated_processes=true')
+
+  cache_path = '%s/files-cache.json' % device_incremental_dir
+  def restore_cache():
+    if not enable_device_cache:
+      logging.info('Ignoring device cache')
+      return
+    # Delete the cached file so that any exceptions cause the next attempt
+    # to re-compute md5s.
+    cmd = 'P=%s;cat $P 2>/dev/null && rm $P' % cache_path
+    lines = device.RunShellCommand(cmd, check_return=False, large_output=True)
+    if lines:
+      device.LoadCacheData(lines[0])
+    else:
+      logging.info('Device cache not found: %s', cache_path)
+
+  def save_cache():
+    cache_data = device.DumpCacheData()
+    device.WriteFile(cache_path, cache_data)
+
+  # Create 2 lock files:
+  # * install.lock tells the app to pause on start-up (until we release it).
+  # * firstrun.lock is used by the app to pause all secondary processes until
+  #   the primary process finishes loading the .dex / .so files.
+  def create_lock_files():
+    # Creates or zeros out lock files.
+    cmd = ('D="%s";'
+           'mkdir -p $D &&'
+           'echo -n >$D/install.lock 2>$D/firstrun.lock')
+    device.RunShellCommand(cmd % device_incremental_dir, check_return=True)
+
+  # The firstrun.lock is released by the app itself.
+  def release_installer_lock():
+    device.RunShellCommand('echo > %s/install.lock' % device_incremental_dir,
+                           check_return=True)
+
+  # Concurrency here speeds things up quite a bit, but DeviceUtils hasn't
+  # been designed for multi-threading. Enabling only because this is a
+  # developer-only tool.
+  setup_timer = _Execute(
+      use_concurrency, create_lock_files, restore_cache, check_selinux)
+
+  _Execute(use_concurrency, do_install, do_push_files)
+
+  finalize_timer = _Execute(use_concurrency, release_installer_lock, save_cache)
+
+  logging.info(
+      'Took %s seconds (setup=%s, install=%s, libs=%s, dex=%s, finalize=%s)',
+      main_timer.GetDelta(), setup_timer.GetDelta(), install_timer.GetDelta(),
+      push_native_timer.GetDelta(), push_dex_timer.GetDelta(),
+      finalize_timer.GetDelta())
+
+
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument('apk_path',
@@ -94,11 +232,6 @@
   if args.output_directory:
     constants.SetOutputDirectory(args.output_directory)
 
-  main_timer = time_profile.TimeProfile()
-  install_timer = time_profile.TimeProfile()
-  push_native_timer = time_profile.TimeProfile()
-  push_dex_timer = time_profile.TimeProfile()
-
   if args.device:
     # Retries are annoying when commands fail for legitimate reasons. Might want
     # to enable them if this is ever used on bots though.
@@ -121,117 +254,14 @@
         msg += '  %s (%s)\n' % (d, desc)
       raise Exception(msg)
 
-  apk = apk_helper.ApkHelper(args.apk_path)
-  apk_package = apk.GetPackageName()
-  device_incremental_dir = '/data/local/tmp/incremental-app-%s' % apk_package
-
+  apk = apk_helper.ToHelper(args.apk_path)
   if args.uninstall:
-    device.Uninstall(apk_package)
-    device.RunShellCommand(['rm', '-rf', device_incremental_dir],
-                           check_return=True)
-    logging.info('Uninstall took %s seconds.', main_timer.GetDelta())
-    return
-
-  # Install .apk(s) if any of them have changed.
-  def do_install():
-    install_timer.Start()
-    if args.splits:
-      splits = []
-      for split_glob in args.splits:
-        splits.extend((f for f in glob.glob(split_glob)))
-      device.InstallSplitApk(apk, splits, reinstall=True,
-                             allow_cached_props=True, permissions=())
-    else:
-      device.Install(apk, reinstall=True, permissions=())
-    install_timer.Stop(log=False)
-
-  # Push .so and .dex files to the device (if they have changed).
-  def do_push_files():
-    if args.lib_dir:
-      push_native_timer.Start()
-      device_lib_dir = posixpath.join(device_incremental_dir, 'lib')
-      device.PushChangedFiles([(args.lib_dir, device_lib_dir)],
-                              delete_device_stale=True)
-      push_native_timer.Stop(log=False)
-
-    if args.dex_files:
-      push_dex_timer.Start()
-      # Put all .dex files to be pushed into a temporary directory so that we
-      # can use delete_device_stale=True.
-      with build_utils.TempDir() as temp_dir:
-        device_dex_dir = posixpath.join(device_incremental_dir, 'dex')
-        # Ensure no two files have the same name.
-        transformed_names = _TransformDexPaths(args.dex_files)
-        for src_path, dest_name in zip(args.dex_files, transformed_names):
-          shutil.copyfile(src_path, os.path.join(temp_dir, dest_name))
-        device.PushChangedFiles([(temp_dir, device_dex_dir)],
-                                delete_device_stale=True)
-      push_dex_timer.Stop(log=False)
-
-  def check_selinux():
-    # Samsung started using SELinux before Marshmallow. There may be even more
-    # cases where this is required...
-    has_selinux = (device.build_version_sdk >= version_codes.MARSHMALLOW or
-                   device.GetProp('selinux.policy_version'))
-    if has_selinux and apk.HasIsolatedProcesses():
-      raise Exception('Cannot use incremental installs on versions of Android '
-                      'where isoloated processes cannot access the filesystem '
-                      '(this includes Android M+, and Samsung L+) without '
-                      'first disabling isoloated processes.\n'
-                      'To do so, use GN arg:\n'
-                      '    disable_incremental_isolated_processes=true')
-
-  cache_path = '%s/files-cache.json' % device_incremental_dir
-  def restore_cache():
-    if not args.cache:
-      logging.info('Ignoring device cache')
-      return
-    # Delete the cached file so that any exceptions cause the next attempt
-    # to re-compute md5s.
-    cmd = 'P=%s;cat $P 2>/dev/null && rm $P' % cache_path
-    lines = device.RunShellCommand(cmd, check_return=False, large_output=True)
-    if lines:
-      device.LoadCacheData(lines[0])
-    else:
-      logging.info('Device cache not found: %s', cache_path)
-
-  def save_cache():
-    cache_data = device.DumpCacheData()
-    device.WriteFile(cache_path, cache_data)
-
-  # Create 2 lock files:
-  # * install.lock tells the app to pause on start-up (until we release it).
-  # * firstrun.lock is used by the app to pause all secondary processes until
-  #   the primary process finishes loading the .dex / .so files.
-  def create_lock_files():
-    # Creates or zeros out lock files.
-    cmd = ('D="%s";'
-           'mkdir -p $D &&'
-           'echo -n >$D/install.lock 2>$D/firstrun.lock')
-    device.RunShellCommand(cmd % device_incremental_dir, check_return=True)
-
-  # The firstrun.lock is released by the app itself.
-  def release_installer_lock():
-    device.RunShellCommand('echo > %s/install.lock' % device_incremental_dir,
-                           check_return=True)
-
-  # Concurrency here speeds things up quite a bit, but DeviceUtils hasn't
-  # been designed for multi-threading. Enabling only because this is a
-  # developer-only tool.
-  setup_timer = _Execute(
-      args.threading, create_lock_files, restore_cache, check_selinux)
-
-  _Execute(args.threading, do_install, do_push_files)
-
-  finalize_timer = _Execute(args.threading, release_installer_lock, save_cache)
-
-  logging.info(
-      'Took %s seconds (setup=%s, install=%s, libs=%s, dex=%s, finalize=%s)',
-      main_timer.GetDelta(), setup_timer.GetDelta(), install_timer.GetDelta(),
-      push_native_timer.GetDelta(), push_dex_timer.GetDelta(),
-      finalize_timer.GetDelta())
+    Uninstall(device, apk.GetPackageName())
+  else:
+    Install(device, apk, split_globs=args.splits, lib_dir=args.lib_dir,
+            dex_files=args.dex_files, enable_device_cache=args.cache,
+            use_concurrency=args.threading)
 
 
 if __name__ == '__main__':
   sys.exit(main())
-
diff --git a/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java
index 81e06a2..e932c1bd 100644
--- a/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java
+++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java
@@ -5,10 +5,13 @@
 package org.chromium.incrementalinstall;
 
 import android.app.Application;
+import android.app.Instrumentation;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
 import android.util.Log;
 
 import java.io.File;
@@ -18,17 +21,23 @@
 
 /**
  * An Application that replaces itself with another Application (as defined in
- * the "incremental-install-real-app" meta-data tag within the
- * AndroidManifest.xml). It loads the other application only after side-loading
- * its .so and .dex files from /data/local/tmp.
+ * an AndroidManifext.xml meta-data tag). It loads the other application only
+ * after side-loading its .so and .dex files from /data/local/tmp.
+ *
+ * This class is highly dependent on the private implementation details of
+ * Android's ActivityThread.java. However, it has been tested to work with
+ * JellyBean through Marshmallow.
  */
 public final class BootstrapApplication extends Application {
     private static final String TAG = "cr.incrementalinstall";
     private static final String MANAGED_DIR_PREFIX = "/data/local/tmp/incremental-app-";
     private static final String REAL_APP_META_DATA_NAME = "incremental-install-real-app";
+    private static final String REAL_INSTRUMENTATION_META_DATA_NAME =
+            "incremental-install-real-instrumentation";
 
     private ClassLoaderPatcher mClassLoaderPatcher;
     private Application mRealApplication;
+    private Instrumentation mRealInstrumentation;
     private Object mStashedProviderList;
     private Object mActivityThread;
 
@@ -65,10 +74,25 @@
                 LockFile.clearInstallerLock(firstRunLockFile);
             }
 
+            Bundle metadata = getManifestMetadata();
+            // mInstrumentationAppDir is one of a set of fields that is initialized only when
+            // instrumentation is active.
+            if (Reflect.getField(mActivityThread, "mInstrumentationAppDir") != null) {
+                initInstrumentation(metadata.getString(REAL_INSTRUMENTATION_META_DATA_NAME));
+            } else {
+                Log.i(TAG, "No instrumentation active.");
+            }
+
+            // Even when instrumentation is not enabled, ActivityThread uses a default
+            // Instrumentation instance internally. We hook it here in order to hook into the
+            // call to Instrumentation.onCreate().
+            Reflect.setField(mActivityThread, "mInstrumentation",
+                    new BootstrapInstrumentation(this));
+
             // attachBaseContext() is called from ActivityThread#handleBindApplication() and
             // Application#mApplication is changed right after we return. Thus, we cannot swap
             // the Application instances until onCreate() is called.
-            String realApplicationName = getRealApplicationName();
+            String realApplicationName = metadata.getString(REAL_APP_META_DATA_NAME);
             Log.i(TAG, "Instantiating " + realApplicationName);
             mRealApplication =
                     (Application) Reflect.newInstance(Class.forName(realApplicationName));
@@ -79,7 +103,49 @@
             // class being installed, so temporarily pretend there are no providers, and then
             // instantiate them explicitly within onCreate().
             disableContentProviders();
-            Log.i(TAG, "Waiting for onCreate");
+            Log.i(TAG, "Waiting for Instrumentation.onCreate");
+        } catch (Exception e) {
+            throw new RuntimeException("Incremental install failed.", e);
+        }
+    }
+
+    /**
+     * Instantiates and initializes mRealInstrumentation (the real Instrumentation class).
+     */
+    private void initInstrumentation(String realInstrumentationName)
+            throws ReflectiveOperationException {
+        Log.i(TAG, "Instantiating instrumentation " + realInstrumentationName);
+        mRealInstrumentation = (Instrumentation) Reflect.newInstance(
+                Class.forName(realInstrumentationName));
+        Instrumentation oldInstrumentation =
+                (Instrumentation) Reflect.getField(mActivityThread, "mInstrumentation");
+
+        // Initialize the fields that are set by Instrumentation.init().
+        String[] initFields = {"mThread", "mMessageQueue", "mInstrContext", "mAppContext",
+                "mWatcher", "mUiAutomationConnection"};
+        for (String fieldName : initFields) {
+            Reflect.setField(mRealInstrumentation, fieldName,
+                    Reflect.getField(oldInstrumentation, fieldName));
+        }
+        // But make sure the correct ComponentName is used.
+        ComponentName newName = new ComponentName(
+                oldInstrumentation.getComponentName().getPackageName(), realInstrumentationName);
+        Reflect.setField(mRealInstrumentation, "mComponent", newName);
+    }
+
+    /**
+     * Called by BootstrapInstrumentation from Instrumentation.onCreate().
+     * This happens regardless of whether or not instrumentation is enabled.
+     */
+    void onInstrumentationCreate(Bundle arguments) {
+        Log.i(TAG, "Instrumentation.onCreate() called. Swapping references.");
+        try {
+            swapApplicationReferences();
+            enableContentProviders();
+            if (mRealInstrumentation != null) {
+                Reflect.setField(mActivityThread, "mInstrumentation", mRealInstrumentation);
+                mRealInstrumentation.onCreate(arguments);
+            }
         } catch (Exception e) {
             throw new RuntimeException("Incremental install failed.", e);
         }
@@ -89,10 +155,7 @@
     public void onCreate() {
         super.onCreate();
         try {
-            Log.i(TAG, "onCreate() called. Swapping Application references");
-            swapApplicationReferences();
-            enableContentProviders();
-            Log.i(TAG, "Calling onCreate");
+            Log.i(TAG, "Application.onCreate() called.");
             mRealApplication.onCreate();
         } catch (Exception e) {
             throw new RuntimeException("Incremental install failed.", e);
@@ -103,10 +166,10 @@
      * Returns the class name of the real Application class (recorded in the
      * AndroidManifest.xml)
      */
-    private String getRealApplicationName() throws NameNotFoundException {
+    private Bundle getManifestMetadata() throws NameNotFoundException {
         ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(),
                 PackageManager.GET_META_DATA);
-        return appInfo.metaData.getString(REAL_APP_META_DATA_NAME);
+        return appInfo.metaData;
     }
 
     /**
diff --git a/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapInstrumentation.java b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapInstrumentation.java
new file mode 100644
index 0000000..f197406
--- /dev/null
+++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapInstrumentation.java
@@ -0,0 +1,25 @@
+// 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.incrementalinstall;
+
+import android.app.Instrumentation;
+import android.os.Bundle;
+
+/**
+ * Notifies BootstrapApplication of the call to Instrumentation.onCreate().
+ */
+public final class BootstrapInstrumentation extends Instrumentation {
+    private final BootstrapApplication mApp;
+
+    BootstrapInstrumentation(BootstrapApplication app) {
+        mApp = app;
+    }
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+        mApp.onInstrumentationCreate(arguments);
+    }
+}
diff --git a/build/android/pylib/gtest/gtest_test_instance.py b/build/android/pylib/gtest/gtest_test_instance.py
index e61b89c..d276592 100644
--- a/build/android/pylib/gtest/gtest_test_instance.py
+++ b/build/android/pylib/gtest/gtest_test_instance.py
@@ -138,9 +138,10 @@
 
     self._shard_timeout = args.shard_timeout
 
+    incremental_part = '_incremental' if args.incremental_install else ''
     apk_path = os.path.join(
         constants.GetOutDirectory(), '%s_apk' % self._suite,
-        '%s-debug.apk' % self._suite)
+        '%s-debug%s.apk' % (self._suite, incremental_part))
     self._exe_path = os.path.join(constants.GetOutDirectory(),
                                   self._suite)
     if not os.path.exists(apk_path):
diff --git a/build/android/pylib/local/device/local_device_environment.py b/build/android/pylib/local/device/local_device_environment.py
index 25ef5828d..b877dbc 100644
--- a/build/android/pylib/local/device/local_device_environment.py
+++ b/build/android/pylib/local/device/local_device_environment.py
@@ -32,6 +32,7 @@
     self._max_tries = 1 + args.num_retries
     self._tool_name = args.tool
     self._enable_device_cache = args.enable_device_cache
+    self._incremental_install = args.incremental_install
 
   #override
   def SetUp(self):
@@ -64,6 +65,10 @@
     return self._devices
 
   @property
+  def incremental_install(self):
+    return self._incremental_install
+
+  @property
   def parallel_devices(self):
     return parallelizer.SyncParallelizer(self.devices)
 
diff --git a/build/android/pylib/local/device/local_device_gtest_run.py b/build/android/pylib/local/device/local_device_gtest_run.py
index 81d85fd..55747ac 100644
--- a/build/android/pylib/local/device/local_device_gtest_run.py
+++ b/build/android/pylib/local/device/local_device_gtest_run.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import imp
 import itertools
 import os
 import posixpath
@@ -9,6 +10,7 @@
 from devil.android import device_errors
 from devil.android import device_temp_file
 from devil.android import ports
+from incremental_install import installer
 from pylib import constants
 from pylib.gtest import gtest_test_instance
 from pylib.local import local_test_server_spawner
@@ -85,12 +87,27 @@
     self._package = test_instance.package
     self._runner = test_instance.runner
     self._permissions = test_instance.permissions
-
+    self._suite = test_instance.suite
     self._component = '%s/%s' % (self._package, self._runner)
     self._extras = test_instance.extras
 
-  def Install(self, device):
-    device.Install(self._apk_helper, permissions=self._permissions)
+  def Install(self, device, incremental=False):
+    if not incremental:
+      device.Install(self._apk_helper, permissions=self._permissions)
+      return
+
+    installer_script = os.path.join(constants.GetOutDirectory(), 'bin',
+                                    'install_%s_apk_incremental' % self._suite)
+    try:
+      install_wrapper = imp.load_source('install_wrapper', installer_script)
+    except IOError:
+      raise Exception(('Incremental install script not found: %s\n'
+                       'Make sure to first build "%s_incremental"') %
+                      (installer_script, self._suite))
+    params = install_wrapper.GetInstallParameters()
+
+    installer.Install(device, self._apk_helper, split_globs=params['splits'],
+                      lib_dir=params['lib_dir'], dex_files=params['dex_files'])
 
   def Run(self, test, device, flags=None, **kwargs):
     extras = dict(self._extras)
@@ -141,7 +158,8 @@
       self._deps_host_path = None
     self._test_run = tr
 
-  def Install(self, device):
+  def Install(self, device, incremental=False):
+    assert not incremental
     # TODO(jbudorick): Look into merging this with normal data deps pushing if
     # executables become supported on nonlocal environments.
     host_device_tuples = [(self._exe_host_path, self._exe_device_path)]
@@ -210,7 +228,7 @@
     @local_device_test_run.handle_shard_failures
     def individual_device_set_up(dev, host_device_tuples):
       # Install test APK.
-      self._delegate.Install(dev)
+      self._delegate.Install(dev, incremental=self._env.incremental_install)
 
       # Push data dependencies.
       external_storage = dev.GetExternalStoragePath()
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index a3a3a98..955e09b 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -188,6 +188,8 @@
   group.add_argument('--blacklist-file', help='Device blacklist file.')
   group.add_argument('--enable-device-cache', action='store_true',
                      help='Cache device state to disk between runs')
+  group.add_argument('--incremental-install', action='store_true',
+                     help='Use an _incremental apk.')
 
 
 def AddGTestOptions(parser):
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 7320db4..a64f14a4 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -1531,17 +1531,6 @@
     if (defined(invoker.args)) {
       args += invoker.args
     }
-
-    if (defined(invoker.renaming_sources) &&
-        defined(invoker.renaming_destinations)) {
-      sources += invoker.renaming_sources
-      rebased_renaming_sources =
-          rebase_path(invoker.renaming_sources, root_build_dir)
-      args += [ "--renaming-sources=$rebased_renaming_sources" ]
-
-      renaming_destinations = invoker.renaming_destinations
-      args += [ "--renaming-destinations=$renaming_destinations" ]
-    }
   }
 }
 
@@ -1672,6 +1661,16 @@
         rebase_path(invoker.isolate_file, root_build_dir),
       ]
     }
+    if (defined(invoker.incremental_install) && invoker.incremental_install) {
+      test_runner_args += [ "--incremental-install" ]
+
+      # These can still be overridden, but make more better defaults during
+      # development.
+      test_runner_args += [
+        "--enable-device-cache",
+        "--num_retries=0",
+      ]
+    }
 
     generated_script = "$root_build_dir/bin/run_${_test_name}"
     outputs = [
diff --git a/cc/base/switches.cc b/cc/base/switches.cc
index 0db15030..9a5b039 100644
--- a/cc/base/switches.cc
+++ b/cc/base/switches.cc
@@ -11,6 +11,12 @@
 
 const char kDisableThreadedAnimation[] = "disable-threaded-animation";
 
+// Disables the use of a cached picture for raster in the renderer,
+// making raster go directly from the display item list (this is the data
+// structure surfaced to tracing). This is useful for debugging to remove
+// the cached picture from the pipeline to narrow down bugs.
+const char kDisableCachedPictureRaster[] = "disable-cached-picture-raster";
+
 // Disables layer-edge anti-aliasing in the compositor.
 const char kDisableCompositedAntialiasing[] =
     "disable-composited-antialiasing";
@@ -44,9 +50,6 @@
 const char kEnablePropertyTreeVerification[] =
     "enable-property-tree-verification";
 
-// Disable partial swap which is needed for some OpenGL drivers / emulators.
-const char kUIDisablePartialSwap[] = "ui-disable-partial-swap";
-
 // Use a BeginFrame signal from browser to renderer to schedule rendering.
 const char kEnableBeginFrameScheduling[] = "enable-begin-frame-scheduling";
 
diff --git a/cc/base/switches.h b/cc/base/switches.h
index 3bce14e..d72b250 100644
--- a/cc/base/switches.h
+++ b/cc/base/switches.h
@@ -17,10 +17,10 @@
 
 // Switches for the renderer compositor only.
 CC_EXPORT extern const char kDisableThreadedAnimation[];
+CC_EXPORT extern const char kDisableCachedPictureRaster[];
 CC_EXPORT extern const char kDisableCompositedAntialiasing[];
 CC_EXPORT extern const char kDisableMainFrameBeforeActivation[];
 CC_EXPORT extern const char kEnableMainFrameBeforeActivation[];
-CC_EXPORT extern const char kJankInsteadOfCheckerboard[];
 CC_EXPORT extern const char kTopControlsHideThreshold[];
 CC_EXPORT extern const char kTopControlsShowThreshold[];
 CC_EXPORT extern const char kSlowDownRasterScaleFactor[];
@@ -28,7 +28,6 @@
 CC_EXPORT extern const char kEnablePropertyTreeVerification[];
 
 // Switches for both the renderer and ui compositors.
-CC_EXPORT extern const char kUIDisablePartialSwap[];
 CC_EXPORT extern const char kEnableBeginFrameScheduling[];
 CC_EXPORT extern const char kEnableGpuBenchmarking[];
 
diff --git a/cc/blink/web_content_layer_impl.cc b/cc/blink/web_content_layer_impl.cc
index 4ccd763..f5ec32b 100644
--- a/cc/blink/web_content_layer_impl.cc
+++ b/cc/blink/web_content_layer_impl.cc
@@ -4,6 +4,8 @@
 
 #include "cc/blink/web_content_layer_impl.h"
 
+#include "base/command_line.h"
+#include "cc/base/switches.h"
 #include "cc/blink/web_display_item_list_impl.h"
 #include "cc/layers/picture_layer.h"
 #include "cc/playback/display_item_list_settings.h"
@@ -18,6 +20,12 @@
 
 namespace cc_blink {
 
+static bool UseCachedPictureRaster() {
+  static bool use = !base::CommandLine::ForCurrentProcess()->HasSwitch(
+      cc::switches::kDisableCachedPictureRaster);
+  return use;
+}
+
 static blink::WebContentLayerClient::PaintingControlSetting
 PaintingControlToWeb(
     cc::ContentLayerClient::PaintingControlSetting painting_control) {
@@ -54,22 +62,12 @@
   layer_->layer()->SetDoubleSided(double_sided);
 }
 
-void WebContentLayerImpl::PaintContents(
-    SkCanvas* canvas,
-    const gfx::Rect& clip,
-    cc::ContentLayerClient::PaintingControlSetting painting_control) {
-  if (!client_)
-    return;
-
-  client_->paintContents(canvas, clip, PaintingControlToWeb(painting_control));
-}
-
 scoped_refptr<cc::DisplayItemList>
 WebContentLayerImpl::PaintContentsToDisplayList(
     const gfx::Rect& clip,
     cc::ContentLayerClient::PaintingControlSetting painting_control) {
   cc::DisplayItemListSettings settings;
-  settings.use_cached_picture = true;
+  settings.use_cached_picture = UseCachedPictureRaster();
 
   scoped_refptr<cc::DisplayItemList> display_list =
       cc::DisplayItemList::Create(clip, settings);
diff --git a/cc/blink/web_content_layer_impl.h b/cc/blink/web_content_layer_impl.h
index fb0fcb7..82956b84 100644
--- a/cc/blink/web_content_layer_impl.h
+++ b/cc/blink/web_content_layer_impl.h
@@ -35,9 +35,6 @@
   ~WebContentLayerImpl() override;
 
   // ContentLayerClient implementation.
-  void PaintContents(SkCanvas* canvas,
-                     const gfx::Rect& clip,
-                     PaintingControlSetting painting_control) override;
   scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       PaintingControlSetting painting_control) override;
diff --git a/cc/layers/content_layer_client.h b/cc/layers/content_layer_client.h
index deb9d619..d56ab6e 100644
--- a/cc/layers/content_layer_client.h
+++ b/cc/layers/content_layer_client.h
@@ -8,8 +8,6 @@
 #include "cc/base/cc_export.h"
 #include "cc/playback/display_item_list.h"
 
-class SkCanvas;
-
 namespace gfx {
 class Rect;
 }
@@ -25,10 +23,6 @@
     DISPLAY_LIST_PAINTING_DISABLED
   };
 
-  virtual void PaintContents(SkCanvas* canvas,
-                             const gfx::Rect& clip,
-                             PaintingControlSetting painting_status) = 0;
-
   virtual scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       PaintingControlSetting painting_status) = 0;
diff --git a/cc/layers/picture_image_layer.cc b/cc/layers/picture_image_layer.cc
index ee12933..f2caeaf 100644
--- a/cc/layers/picture_image_layer.cc
+++ b/cc/layers/picture_image_layer.cc
@@ -49,14 +49,23 @@
   SetNeedsDisplay();
 }
 
-void PictureImageLayer::PaintContents(
-    SkCanvas* canvas,
+scoped_refptr<DisplayItemList> PictureImageLayer::PaintContentsToDisplayList(
     const gfx::Rect& clip,
     ContentLayerClient::PaintingControlSetting painting_control) {
   DCHECK(image_);
   DCHECK_GT(image_->width(), 0);
   DCHECK_GT(image_->height(), 0);
 
+  // Picture image layers can be used with GatherPixelRefs, so cached SkPictures
+  // are currently required.
+  DisplayItemListSettings settings;
+  settings.use_cached_picture = true;
+  scoped_refptr<DisplayItemList> display_list =
+      DisplayItemList::Create(clip, settings);
+
+  SkPictureRecorder recorder;
+  SkCanvas* canvas = recorder.beginRecording(gfx::RectToSkRect(clip));
+
   SkScalar content_to_layer_scale_x =
       SkFloatToScalar(static_cast<float>(bounds().width()) / image_->width());
   SkScalar content_to_layer_scale_y =
@@ -67,21 +76,6 @@
   // to the root canvas, this draw must use the kSrcOver_Mode so that
   // transparent images blend correctly.
   canvas->drawImage(image_.get(), 0, 0);
-}
-
-scoped_refptr<DisplayItemList> PictureImageLayer::PaintContentsToDisplayList(
-    const gfx::Rect& clip,
-    ContentLayerClient::PaintingControlSetting painting_control) {
-  // Picture image layers can be used with GatherPixelRefs, so cached SkPictures
-  // are currently required.
-  DisplayItemListSettings settings;
-  settings.use_cached_picture = true;
-  scoped_refptr<DisplayItemList> display_list =
-      DisplayItemList::Create(clip, settings);
-
-  SkPictureRecorder recorder;
-  SkCanvas* canvas = recorder.beginRecording(gfx::RectToSkRect(clip));
-  PaintContents(canvas, clip, painting_control);
 
   skia::RefPtr<SkPicture> picture =
       skia::AdoptRef(recorder.endRecordingAsPicture());
diff --git a/cc/layers/picture_image_layer.h b/cc/layers/picture_image_layer.h
index df306868..a283c45 100644
--- a/cc/layers/picture_image_layer.h
+++ b/cc/layers/picture_image_layer.h
@@ -25,10 +25,6 @@
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
 
   // ContentLayerClient implementation.
-  void PaintContents(
-      SkCanvas* canvas,
-      const gfx::Rect& clip,
-      ContentLayerClient::PaintingControlSetting painting_control) override;
   scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       ContentLayerClient::PaintingControlSetting painting_control) override;
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc
index 2f5b55f..dffbad4 100644
--- a/cc/layers/picture_layer_unittest.cc
+++ b/cc/layers/picture_layer_unittest.cc
@@ -23,9 +23,6 @@
 
 class MockContentLayerClient : public ContentLayerClient {
  public:
-  void PaintContents(SkCanvas* canvas,
-                     const gfx::Rect& clip,
-                     PaintingControlSetting picture_control) override {}
   scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       PaintingControlSetting picture_control) override {
diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc
index 16987cb8..e3b0f5ec 100644
--- a/cc/surfaces/surface.cc
+++ b/cc/surfaces/surface.cc
@@ -98,11 +98,22 @@
 
 void Surface::RequestCopyOfOutput(scoped_ptr<CopyOutputRequest> copy_request) {
   if (current_frame_ &&
-      !current_frame_->delegated_frame_data->render_pass_list.empty())
-    current_frame_->delegated_frame_data->render_pass_list.back()
-        ->copy_requests.push_back(copy_request.Pass());
-  else
+      !current_frame_->delegated_frame_data->render_pass_list.empty()) {
+    ScopedPtrVector<CopyOutputRequest>& copy_requests =
+        current_frame_->delegated_frame_data->render_pass_list.back()
+            ->copy_requests;
+
+    if (void* source = copy_request->source()) {
+      // Remove existing CopyOutputRequests made on the Surface by the same
+      // source.
+      auto to_remove = copy_requests.remove_if([source](
+          const CopyOutputRequest* x) { return x->source() == source; });
+      copy_requests.erase(to_remove, copy_requests.end());
+    }
+    copy_requests.push_back(copy_request.Pass());
+  } else {
     copy_request->SendEmptyResult();
+  }
 }
 
 void Surface::TakeCopyOutputRequests(
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc
index 69618ba8b..902f836 100644
--- a/cc/surfaces/surface_aggregator.cc
+++ b/cc/surfaces/surface_aggregator.cc
@@ -547,9 +547,6 @@
   if (provider_)
     provider_->DeclareUsedResourcesFromChild(child_id, referenced_resources);
 
-  for (const auto& render_pass : frame_data->render_pass_list)
-    has_copy_requests_ |= !render_pass->copy_requests.empty();
-
   gfx::Rect damage_rect;
   if (!frame_data->render_pass_list.empty()) {
     RenderPass* last_pass = frame_data->render_pass_list.back();
@@ -566,6 +563,13 @@
     damage_rect.Union(
         MathUtil::MapEnclosingClippedRect(surface_info.second, surface_damage));
   }
+
+  if (surface->factory())
+    surface->factory()->WillDrawSurface(surface->surface_id(), damage_rect);
+
+  for (const auto& render_pass : frame_data->render_pass_list)
+    has_copy_requests_ |= !render_pass->copy_requests.empty();
+
   referenced_surfaces_.erase(it);
   return damage_rect;
 }
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
index bfec6e6..bee479c 100644
--- a/cc/surfaces/surface_aggregator_unittest.cc
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -43,6 +43,13 @@
 class EmptySurfaceFactoryClient : public SurfaceFactoryClient {
  public:
   void ReturnResources(const ReturnedResourceArray& resources) override {}
+  void WillDrawSurface(SurfaceId id, const gfx::Rect& damage_rect) override {
+    last_surface_id_ = id;
+    last_damage_rect_ = damage_rect;
+  }
+
+  gfx::Rect last_damage_rect_;
+  SurfaceId last_surface_id_;
 };
 
 class SurfaceAggregatorTest : public testing::Test {
@@ -166,6 +173,10 @@
 
   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_surface_id_, empty_client_.last_surface_id_);
 }
 
 TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) {
diff --git a/cc/surfaces/surface_factory.cc b/cc/surfaces/surface_factory.cc
index 3e83c8c..72ebdc40d 100644
--- a/cc/surfaces/surface_factory.cc
+++ b/cc/surfaces/surface_factory.cc
@@ -8,6 +8,7 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_factory_client.h"
 #include "cc/surfaces/surface_manager.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -75,6 +76,11 @@
   manager_->SurfaceModified(surface_id);
 }
 
+void SurfaceFactory::WillDrawSurface(SurfaceId id,
+                                     const gfx::Rect& damage_rect) {
+  client_->WillDrawSurface(id, damage_rect);
+}
+
 void SurfaceFactory::ReceiveFromChild(
     const TransferableResourceArray& resources) {
   holder_.ReceiveFromChild(resources);
diff --git a/cc/surfaces/surface_factory.h b/cc/surfaces/surface_factory.h
index 5af8d2e..762d5a2 100644
--- a/cc/surfaces/surface_factory.h
+++ b/cc/surfaces/surface_factory.h
@@ -11,6 +11,7 @@
 #include "base/containers/scoped_ptr_hash_map.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/surfaces/surface_id.h"
 #include "cc/surfaces/surface_resource_holder.h"
@@ -55,6 +56,8 @@
   void RequestCopyOfSurface(SurfaceId surface_id,
                             scoped_ptr<CopyOutputRequest> copy_request);
 
+  void WillDrawSurface(SurfaceId id, const gfx::Rect& damage_rect);
+
   SurfaceFactoryClient* client() { return client_; }
 
   void ReceiveFromChild(const TransferableResourceArray& resources);
diff --git a/cc/surfaces/surface_factory_client.h b/cc/surfaces/surface_factory_client.h
index 9866b27..c2a04af6 100644
--- a/cc/surfaces/surface_factory_client.h
+++ b/cc/surfaces/surface_factory_client.h
@@ -6,7 +6,9 @@
 #define CC_SURFACES_SURFACE_FACTORY_CLIENT_H_
 
 #include "cc/resources/returned_resource.h"
+#include "cc/surfaces/surface_id.h"
 #include "cc/surfaces/surfaces_export.h"
+#include "ui/gfx/geometry/rect.h"
 
 namespace cc {
 
@@ -15,6 +17,9 @@
   virtual ~SurfaceFactoryClient() {}
 
   virtual void ReturnResources(const ReturnedResourceArray& resources) = 0;
+
+  virtual void WillDrawSurface(SurfaceId surface_id,
+                               const gfx::Rect& damage_rect) {}
 };
 
 }  // namespace cc
diff --git a/cc/surfaces/surface_factory_unittest.cc b/cc/surfaces/surface_factory_unittest.cc
index c7ce9640..9629a4e 100644
--- a/cc/surfaces/surface_factory_unittest.cc
+++ b/cc/surfaces/surface_factory_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "base/bind.h"
 #include "cc/output/compositor_frame.h"
+#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
 #include "cc/output/delegated_frame_data.h"
 #include "cc/resources/resource_provider.h"
 #include "cc/surfaces/surface.h"
@@ -519,5 +521,61 @@
   surface_id_ = SurfaceId();
 }
 
+void CopyRequestTestCallback(bool* called,
+                             scoped_ptr<CopyOutputResult> result) {
+  *called = true;
+}
+
+TEST_F(SurfaceFactoryTest, DuplicateCopyRequest) {
+  {
+    scoped_ptr<RenderPass> render_pass(RenderPass::Create());
+    render_pass->referenced_surfaces.push_back(surface_id_);
+    scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+    frame_data->render_pass_list.push_back(render_pass.Pass());
+    scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+    frame->delegated_frame_data = frame_data.Pass();
+    factory_.SubmitCompositorFrame(surface_id_, frame.Pass(),
+                                   SurfaceFactory::DrawCallback());
+  }
+  void* source1 = &source1;
+  void* source2 = &source2;
+
+  bool called1 = false;
+  scoped_ptr<CopyOutputRequest> request;
+  request = CopyOutputRequest::CreateRequest(
+      base::Bind(&CopyRequestTestCallback, &called1));
+  request->set_source(source1);
+
+  factory_.RequestCopyOfSurface(surface_id_, request.Pass());
+  EXPECT_FALSE(called1);
+
+  bool called2 = false;
+  request = CopyOutputRequest::CreateRequest(
+      base::Bind(&CopyRequestTestCallback, &called2));
+  request->set_source(source2);
+
+  factory_.RequestCopyOfSurface(surface_id_, request.Pass());
+  // Callbacks have different sources so neither should be called.
+  EXPECT_FALSE(called1);
+  EXPECT_FALSE(called2);
+
+  bool called3 = false;
+  request = CopyOutputRequest::CreateRequest(
+      base::Bind(&CopyRequestTestCallback, &called3));
+  request->set_source(source1);
+
+  factory_.RequestCopyOfSurface(surface_id_, request.Pass());
+  // Two callbacks are from source1, so the first should be called.
+  EXPECT_TRUE(called1);
+  EXPECT_FALSE(called2);
+  EXPECT_FALSE(called3);
+
+  factory_.Destroy(surface_id_);
+  surface_id_ = SurfaceId();
+  EXPECT_TRUE(called1);
+  EXPECT_TRUE(called2);
+  EXPECT_TRUE(called3);
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/test/fake_content_layer_client.cc b/cc/test/fake_content_layer_client.cc
index eb95c38..bfa7c19 100644
--- a/cc/test/fake_content_layer_client.cc
+++ b/cc/test/fake_content_layer_client.cc
@@ -35,39 +35,6 @@
 FakeContentLayerClient::~FakeContentLayerClient() {
 }
 
-void FakeContentLayerClient::PaintContents(
-    SkCanvas* canvas,
-    const gfx::Rect& paint_rect,
-    PaintingControlSetting painting_control) {
-  last_canvas_ = canvas;
-  last_painting_control_ = painting_control;
-
-  canvas->clipRect(gfx::RectToSkRect(paint_rect));
-  for (RectPaintVector::const_iterator it = draw_rects_.begin();
-      it != draw_rects_.end(); ++it) {
-    const gfx::RectF& draw_rect = it->first;
-    const SkPaint& paint = it->second;
-    canvas->drawRect(gfx::RectFToSkRect(draw_rect), paint);
-  }
-
-  for (ImageVector::const_iterator it = draw_images_.begin();
-       it != draw_images_.end(); ++it) {
-    canvas->drawImage(it->image.get(), it->point.x(), it->point.y(),
-                      &it->paint);
-  }
-
-  if (fill_with_nonsolid_color_) {
-    gfx::Rect draw_rect = paint_rect;
-    bool red = true;
-    while (!draw_rect.IsEmpty()) {
-      SkPaint paint;
-      paint.setColor(red ? SK_ColorRED : SK_ColorBLUE);
-      canvas->drawIRect(gfx::RectToSkIRect(draw_rect), paint);
-      draw_rect.Inset(1, 1);
-    }
-  }
-}
-
 scoped_refptr<DisplayItemList>
 FakeContentLayerClient::PaintContentsToDisplayList(
     const gfx::Rect& clip,
diff --git a/cc/test/fake_content_layer_client.h b/cc/test/fake_content_layer_client.h
index ead804ab..e24fee7e 100644
--- a/cc/test/fake_content_layer_client.h
+++ b/cc/test/fake_content_layer_client.h
@@ -38,9 +38,6 @@
   FakeContentLayerClient();
   ~FakeContentLayerClient() override;
 
-  void PaintContents(SkCanvas* canvas,
-                     const gfx::Rect& rect,
-                     PaintingControlSetting painting_control) override;
   scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       PaintingControlSetting painting_control) override;
diff --git a/cc/test/solid_color_content_layer_client.cc b/cc/test/solid_color_content_layer_client.cc
index bf9ac345..ed84bec4 100644
--- a/cc/test/solid_color_content_layer_client.cc
+++ b/cc/test/solid_color_content_layer_client.cc
@@ -15,17 +15,6 @@
 
 namespace cc {
 
-// TODO(pdr): Remove PaintContents as all calls should go through
-// PaintContentsToDisplayList.
-void SolidColorContentLayerClient::PaintContents(
-    SkCanvas* canvas,
-    const gfx::Rect& rect,
-    PaintingControlSetting painting_control) {
-  scoped_refptr<DisplayItemList> contents =
-      PaintContentsToDisplayList(rect, painting_control);
-  contents->Raster(canvas, nullptr, rect, 1.0f);
-}
-
 scoped_refptr<DisplayItemList>
 SolidColorContentLayerClient::PaintContentsToDisplayList(
     const gfx::Rect& clip,
diff --git a/cc/test/solid_color_content_layer_client.h b/cc/test/solid_color_content_layer_client.h
index 5ad35993..c39d567c 100644
--- a/cc/test/solid_color_content_layer_client.h
+++ b/cc/test/solid_color_content_layer_client.h
@@ -16,9 +16,6 @@
   explicit SolidColorContentLayerClient(SkColor color) : color_(color) {}
 
   // ContentLayerClient implementation.
-  void PaintContents(SkCanvas* canvas,
-                     const gfx::Rect& rect,
-                     PaintingControlSetting painting_control) override;
   scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       PaintingControlSetting painting_control) override;
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 1554142..5969636 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -682,7 +682,7 @@
   return gfx::ToEnclosingRect(parent_clip_node->data.clip_in_target_space);
 }
 
-gfx::Transform SurfaceScreenSpaceTransform(
+gfx::Transform SurfaceScreenSpaceTransformFromPropertyTrees(
     const RenderSurfaceImpl* render_surface,
     const TransformTree& tree) {
   const TransformNode* node = tree.Node(render_surface->TransformTreeIndex());
@@ -888,8 +888,9 @@
       SurfaceDrawOpacity(render_surface, property_trees->effect_tree);
   draw_properties->draw_transform =
       SurfaceDrawTransform(render_surface, property_trees->transform_tree);
-  draw_properties->screen_space_transform = SurfaceScreenSpaceTransform(
-      render_surface, property_trees->transform_tree);
+  draw_properties->screen_space_transform =
+      SurfaceScreenSpaceTransformFromPropertyTrees(
+          render_surface, property_trees->transform_tree);
 
   if (render_surface->HasReplica()) {
     gfx::Transform replica_to_surface = ReplicaToSurfaceTransform(
diff --git a/cc/trees/draw_property_utils.h b/cc/trees/draw_property_utils.h
index 2200959..858f0fc 100644
--- a/cc/trees/draw_property_utils.h
+++ b/cc/trees/draw_property_utils.h
@@ -103,6 +103,10 @@
 ScreenSpaceTransformFromPropertyTrees(const LayerImpl* layer,
                                       const TransformTree& tree);
 
+gfx::Transform CC_EXPORT SurfaceScreenSpaceTransformFromPropertyTrees(
+    const RenderSurfaceImpl* render_surface,
+    const TransformTree& tree);
+
 void CC_EXPORT
 UpdatePageScaleFactorInPropertyTrees(PropertyTrees* property_trees,
                                      const LayerImpl* page_scale_layer,
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index ac77ea4..0bc190c 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -60,9 +60,6 @@
  public:
   MockContentLayerClient() {}
   ~MockContentLayerClient() override {}
-  void PaintContents(SkCanvas* canvas,
-                     const gfx::Rect& clip,
-                     PaintingControlSetting picture_control) override {}
   scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       PaintingControlSetting picture_control) override {
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc
index ce9dde5..929d8c0 100644
--- a/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -32,16 +32,6 @@
   bool FillsBoundsCompletely() const override { return false; }
   size_t GetApproximateUnsharedMemoryUsage() const override { return 0; }
 
-  // TODO(pdr): Remove PaintContents as all calls should go through
-  // PaintContentsToDisplayList.
-  void PaintContents(SkCanvas* canvas,
-                     const gfx::Rect& rect,
-                     PaintingControlSetting picture_control) override {
-    scoped_refptr<DisplayItemList> contents =
-        PaintContentsToDisplayList(rect, picture_control);
-    contents->Raster(canvas, nullptr, rect, 1.0f);
-  }
-
   scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       PaintingControlSetting picture_control) override {
@@ -119,8 +109,10 @@
   SkCanvas* canvas = surface->getCanvas();
   canvas->scale(SkIntToScalar(4), SkIntToScalar(4));
   MaskContentLayerClient client(mask_bounds);
-  client.PaintContents(canvas, gfx::Rect(mask_bounds),
-                       ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+  scoped_refptr<DisplayItemList> mask_display_list =
+      client.PaintContentsToDisplayList(
+          gfx::Rect(mask_bounds), ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+  mask_display_list->Raster(canvas, nullptr, gfx::Rect(mask_bounds), 1.0f);
   skia::RefPtr<const SkImage> image =
       skia::AdoptRef(surface->newImageSnapshot());
   mask->SetImage(image.Pass());
@@ -319,15 +311,6 @@
   ~CheckerContentLayerClient() override {}
   bool FillsBoundsCompletely() const override { return false; }
   size_t GetApproximateUnsharedMemoryUsage() const override { return 0; }
-  // TODO(pdr): Remove PaintContents as all calls should go through
-  // PaintContentsToDisplayList.
-  void PaintContents(SkCanvas* canvas,
-                     const gfx::Rect& rect,
-                     PaintingControlSetting picture_control) override {
-    scoped_refptr<DisplayItemList> contents =
-        PaintContentsToDisplayList(rect, picture_control);
-    contents->Raster(canvas, nullptr, rect, 1.0f);
-  }
   scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       PaintingControlSetting picture_control) override {
@@ -375,15 +358,6 @@
   ~CircleContentLayerClient() override {}
   bool FillsBoundsCompletely() const override { return false; }
   size_t GetApproximateUnsharedMemoryUsage() const override { return 0; }
-  // TODO(pdr): Remove PaintContents as all calls should go through
-  // PaintContentsToDisplayList.
-  void PaintContents(SkCanvas* canvas,
-                     const gfx::Rect& rect,
-                     PaintingControlSetting picture_control) override {
-    scoped_refptr<DisplayItemList> contents =
-        PaintContentsToDisplayList(rect, picture_control);
-    contents->Raster(canvas, nullptr, rect, 1.0f);
-  }
   scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       PaintingControlSetting picture_control) override {
diff --git a/cc/trees/layer_tree_host_pixeltest_tiles.cc b/cc/trees/layer_tree_host_pixeltest_tiles.cc
index f013e98..0d036fb 100644
--- a/cc/trees/layer_tree_host_pixeltest_tiles.cc
+++ b/cc/trees/layer_tree_host_pixeltest_tiles.cc
@@ -92,10 +92,6 @@
   explicit BlueYellowClient(const gfx::Size& size)
       : size_(size), blue_top_(true) {}
 
-  void PaintContents(SkCanvas* canvas,
-                     const gfx::Rect& clip,
-                     PaintingControlSetting painting_status) override {}
-
   scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       PaintingControlSetting painting_status) override {
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index d3c67d7..e75b3e9 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1553,11 +1553,6 @@
 
   void SetTestLayer(Layer* test_layer) { test_layer_ = test_layer; }
 
-  void PaintContents(SkCanvas* canvas,
-                     const gfx::Rect& clip,
-                     PaintingControlSetting picture_control) override {
-    NOTIMPLEMENTED();
-  }
   scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       PaintingControlSetting picture_control) override {
@@ -2159,12 +2154,6 @@
 
     void set_layer(Layer* layer) { layer_ = layer; }
 
-    void PaintContents(SkCanvas* canvas,
-                       const gfx::Rect& clip,
-                       PaintingControlSetting picture_control) override {
-      NOTIMPLEMENTED();
-    }
-
     scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
         const gfx::Rect& clip,
         PaintingControlSetting picture_control) override {
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index dda446a8..a77e517 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -26,6 +26,7 @@
 #include "cc/layers/render_surface_impl.h"
 #include "cc/layers/scrollbar_layer_impl_base.h"
 #include "cc/resources/ui_resource_request.h"
+#include "cc/trees/draw_property_utils.h"
 #include "cc/trees/layer_tree_host_common.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/occlusion_tracker.h"
@@ -1375,21 +1376,52 @@
   return layer->parent();
 }
 
+static const gfx::Transform LayerScreenSpaceTransform(
+    const LayerImpl* layer,
+    const TransformTree& transform_tree,
+    const bool use_property_trees) {
+  if (!use_property_trees)
+    return layer->screen_space_transform();
+  // When we use property trees, UpdateDrawProperties does not update the draw
+  // properties of a layer that is not in render surface layer list, so we need
+  // to compute the screen space transform.
+  return layer->IsDrawnRenderSurfaceLayerListMember()
+             ? layer->screen_space_transform()
+             : ScreenSpaceTransformFromPropertyTrees(layer, transform_tree);
+}
+
+static const gfx::Transform SurfaceScreenSpaceTransform(
+    const LayerImpl* layer,
+    const TransformTree& transform_tree,
+    const bool use_property_trees) {
+  DCHECK(layer->render_surface());
+  if (!use_property_trees)
+    return layer->render_surface()->screen_space_transform();
+  return layer->IsDrawnRenderSurfaceLayerListMember()
+             ? layer->render_surface()->screen_space_transform()
+             : SurfaceScreenSpaceTransformFromPropertyTrees(
+                   layer->render_surface(), transform_tree);
+}
+
 static bool PointIsClippedBySurfaceOrClipRect(
     const gfx::PointF& screen_space_point,
-    const LayerImpl* layer) {
+    const LayerImpl* layer,
+    const TransformTree& transform_tree,
+    const bool use_property_trees) {
   // Walk up the layer tree and hit-test any render_surfaces and any layer
   // clip rects that are active.
   for (; layer; layer = GetNextClippingLayer(layer)) {
     if (layer->render_surface() &&
         !PointHitsRect(screen_space_point,
-                       layer->render_surface()->screen_space_transform(),
-                       layer->render_surface()->content_rect(),
-                       NULL))
+                       SurfaceScreenSpaceTransform(layer, transform_tree,
+                                                   use_property_trees),
+                       layer->render_surface()->content_rect(), NULL))
       return true;
 
     if (LayerClipsSubtree(layer) &&
-        !PointHitsRect(screen_space_point, layer->screen_space_transform(),
+        !PointHitsRect(screen_space_point,
+                       LayerScreenSpaceTransform(layer, transform_tree,
+                                                 use_property_trees),
                        gfx::Rect(layer->bounds()), NULL))
       return true;
   }
@@ -1401,18 +1433,21 @@
 
 static bool PointHitsLayer(const LayerImpl* layer,
                            const gfx::PointF& screen_space_point,
-                           float* distance_to_intersection) {
+                           float* distance_to_intersection,
+                           const TransformTree& transform_tree,
+                           const bool use_property_trees) {
   gfx::Rect content_rect(layer->bounds());
-  if (!PointHitsRect(screen_space_point,
-                     layer->screen_space_transform(),
-                     content_rect,
-                     distance_to_intersection))
+  if (!PointHitsRect(
+          screen_space_point,
+          LayerScreenSpaceTransform(layer, transform_tree, use_property_trees),
+          content_rect, distance_to_intersection))
     return false;
 
   // At this point, we think the point does hit the layer, but we need to walk
   // up the parents to ensure that the layer was not clipped in such a way
   // that the hit point actually should not hit the layer.
-  if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer))
+  if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer,
+                                        transform_tree, use_property_trees))
     return false;
 
   // Skip the HUD layer.
@@ -1437,17 +1472,21 @@
     const gfx::PointF& screen_space_point,
     LayerImpl* layer,
     const Functor& func,
+    const TransformTree& transform_tree,
+    const bool use_property_trees,
     FindClosestMatchingLayerDataForRecursion* data_for_recursion) {
   size_t children_size = layer->children().size();
   for (size_t i = 0; i < children_size; ++i) {
     size_t index = children_size - 1 - i;
     FindClosestMatchingLayer(screen_space_point, layer->children()[index], func,
+                             transform_tree, use_property_trees,
                              data_for_recursion);
   }
 
   float distance_to_intersection = 0.f;
   if (func(layer) &&
-      PointHitsLayer(layer, screen_space_point, &distance_to_intersection) &&
+      PointHitsLayer(layer, screen_space_point, &distance_to_intersection,
+                     transform_tree, use_property_trees) &&
       ((!data_for_recursion->closest_match ||
         distance_to_intersection > data_for_recursion->closest_distance))) {
     data_for_recursion->closest_distance = distance_to_intersection;
@@ -1482,10 +1521,10 @@
 LayerImpl* LayerTreeImpl::FindFirstScrollingLayerThatIsHitByPoint(
     const gfx::PointF& screen_space_point) {
   FindClosestMatchingLayerDataForRecursion data_for_recursion;
-  FindClosestMatchingLayer(screen_space_point,
-                           root_layer(),
-                           FindScrollingLayerFunctor(),
-                           &data_for_recursion);
+  FindClosestMatchingLayer(
+      screen_space_point, root_layer(), FindScrollingLayerFunctor(),
+      property_trees_.transform_tree, settings().verify_property_trees,
+      &data_for_recursion);
   return data_for_recursion.closest_match;
 }
 
@@ -1506,19 +1545,24 @@
   if (!UpdateDrawProperties(update_lcd_text))
     return NULL;
   FindClosestMatchingLayerDataForRecursion data_for_recursion;
-  FindClosestMatchingLayer(screen_space_point,
-                           root_layer(),
+  FindClosestMatchingLayer(screen_space_point, root_layer(),
                            HitTestVisibleScrollableOrTouchableFunctor(),
+                           property_trees_.transform_tree,
+                           settings().verify_property_trees,
                            &data_for_recursion);
   return data_for_recursion.closest_match;
 }
 
 static bool LayerHasTouchEventHandlersAt(const gfx::PointF& screen_space_point,
-                                         LayerImpl* layer_impl) {
+                                         LayerImpl* layer_impl,
+                                         const TransformTree& transform_tree,
+                                         const bool use_property_trees) {
   if (layer_impl->touch_event_handler_region().IsEmpty())
     return false;
 
-  if (!PointHitsRegion(screen_space_point, layer_impl->screen_space_transform(),
+  if (!PointHitsRegion(screen_space_point,
+                       LayerScreenSpaceTransform(layer_impl, transform_tree,
+                                                 use_property_trees),
                        layer_impl->touch_event_handler_region()))
     return false;
 
@@ -1526,7 +1570,8 @@
   // on the layer, but we need to walk up the parents to ensure that the layer
   // was not clipped in such a way that the hit point actually should not hit
   // the layer.
-  if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer_impl))
+  if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer_impl,
+                                        transform_tree, use_property_trees))
     return false;
 
   return true;
@@ -1547,16 +1592,20 @@
     return NULL;
   FindWheelEventLayerFunctor func;
   FindClosestMatchingLayerDataForRecursion data_for_recursion;
-  FindClosestMatchingLayer(screen_space_point, root_layer(), func,
-                           &data_for_recursion);
+  FindClosestMatchingLayer(
+      screen_space_point, root_layer(), func, property_trees_.transform_tree,
+      settings().verify_property_trees, &data_for_recursion);
   return data_for_recursion.closest_match;
 }
 
 struct FindTouchEventLayerFunctor {
   bool operator()(LayerImpl* layer) const {
-    return LayerHasTouchEventHandlersAt(screen_space_point, layer);
+    return LayerHasTouchEventHandlersAt(screen_space_point, layer,
+                                        transform_tree, use_property_trees);
   }
   const gfx::PointF screen_space_point;
+  const TransformTree& transform_tree;
+  const bool use_property_trees;
 };
 
 LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInTouchHandlerRegion(
@@ -1566,10 +1615,13 @@
   bool update_lcd_text = false;
   if (!UpdateDrawProperties(update_lcd_text))
     return NULL;
-  FindTouchEventLayerFunctor func = {screen_space_point};
+  FindTouchEventLayerFunctor func = {screen_space_point,
+                                     property_trees_.transform_tree,
+                                     settings().verify_property_trees};
   FindClosestMatchingLayerDataForRecursion data_for_recursion;
   FindClosestMatchingLayer(
-      screen_space_point, root_layer(), func, &data_for_recursion);
+      screen_space_point, root_layer(), func, property_trees_.transform_tree,
+      settings().verify_property_trees, &data_for_recursion);
   return data_for_recursion.closest_match;
 }
 
@@ -1580,7 +1632,9 @@
 static ViewportSelectionBound ComputeViewportSelectionBound(
     const LayerSelectionBound& layer_bound,
     LayerImpl* layer,
-    float device_scale_factor) {
+    float device_scale_factor,
+    const TransformTree& transform_tree,
+    const bool use_property_trees) {
   ViewportSelectionBound viewport_bound;
   viewport_bound.type = layer_bound.type;
 
@@ -1589,12 +1643,14 @@
 
   gfx::PointF layer_top = layer_bound.edge_top;
   gfx::PointF layer_bottom = layer_bound.edge_bottom;
+  gfx::Transform screen_space_transform =
+      LayerScreenSpaceTransform(layer, transform_tree, use_property_trees);
 
   bool clipped = false;
   gfx::PointF screen_top =
-      MathUtil::MapPoint(layer->screen_space_transform(), layer_top, &clipped);
-  gfx::PointF screen_bottom = MathUtil::MapPoint(
-      layer->screen_space_transform(), layer_bottom, &clipped);
+      MathUtil::MapPoint(screen_space_transform, layer_top, &clipped);
+  gfx::PointF screen_bottom =
+      MathUtil::MapPoint(screen_space_transform, layer_bottom, &clipped);
 
   // MapPoint can produce points with NaN components (even when no inputs are
   // NaN). Since consumers of ViewportSelectionBounds may round |edge_top| or
@@ -1618,12 +1674,13 @@
   gfx::PointF visibility_point = layer_bottom + visibility_offset;
   if (visibility_point.x() <= 0)
     visibility_point.set_x(visibility_point.x() + device_scale_factor);
-  visibility_point = MathUtil::MapPoint(
-      layer->screen_space_transform(), visibility_point, &clipped);
+  visibility_point =
+      MathUtil::MapPoint(screen_space_transform, visibility_point, &clipped);
 
   float intersect_distance = 0.f;
   viewport_bound.visible =
-      PointHitsLayer(layer, visibility_point, &intersect_distance);
+      PointHitsLayer(layer, visibility_point, &intersect_distance,
+                     transform_tree, use_property_trees);
 
   return viewport_bound;
 }
@@ -1634,7 +1691,8 @@
   selection->start = ComputeViewportSelectionBound(
       selection_.start,
       selection_.start.layer_id ? LayerById(selection_.start.layer_id) : NULL,
-      device_scale_factor());
+      device_scale_factor(), property_trees_.transform_tree,
+      settings().verify_property_trees);
   selection->is_editable = selection_.is_editable;
   selection->is_empty_text_form_control = selection_.is_empty_text_form_control;
   if (selection->start.type == SELECTION_BOUND_CENTER ||
@@ -1644,7 +1702,8 @@
     selection->end = ComputeViewportSelectionBound(
         selection_.end,
         selection_.end.layer_id ? LayerById(selection_.end.layer_id) : NULL,
-        device_scale_factor());
+        device_scale_factor(), property_trees_.transform_tree,
+        settings().verify_property_trees);
   }
 }
 
diff --git a/cc/trees/layer_tree_impl_unittest.cc b/cc/trees/layer_tree_impl_unittest.cc
index 182dff1..3c6a453 100644
--- a/cc/trees/layer_tree_impl_unittest.cc
+++ b/cc/trees/layer_tree_impl_unittest.cc
@@ -1456,7 +1456,8 @@
   EXPECT_EQ(gfx::Rect(test_layer->bounds()), test_layer->visible_layer_rect());
 
   // Hit checking for a point outside the layer should return a null pointer
-  // (the root layer does not draw content, so it will not be tested either).
+  // (the root layer does not have a touch event handler, so it will not be
+  // tested either).
   gfx::PointF test_point(76.f, 76.f);
   test_point =
       gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
@@ -1711,6 +1712,79 @@
   EXPECT_FALSE(result_layer);
 }
 
+TEST_F(LayerTreeImplTest, HitTestingTouchHandlerRegionsForLayerThatIsNotDrawn) {
+  scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+
+  gfx::Transform identity_matrix;
+  gfx::Point3F transform_origin;
+  SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+                               gfx::PointF(), gfx::Size(100, 100), true, false,
+                               true);
+  root->SetDrawsContent(true);
+  {
+    Region touch_handler_region(gfx::Rect(10, 10, 30, 30));
+    gfx::PointF position;
+    gfx::Size bounds(50, 50);
+    scoped_ptr<LayerImpl> test_layer =
+        LayerImpl::Create(host_impl().active_tree(), 12345);
+    SetLayerPropertiesForTesting(test_layer.get(), identity_matrix,
+                                 transform_origin, position, bounds, true,
+                                 false, false);
+
+    test_layer->SetDrawsContent(false);
+    test_layer->SetTouchEventHandlerRegion(touch_handler_region);
+    root->AddChild(test_layer.Pass());
+  }
+  host_impl().SetViewportSize(root->bounds());
+  host_impl().active_tree()->SetRootLayer(root.Pass());
+  host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
+
+  LayerImpl* test_layer =
+      host_impl().active_tree()->root_layer()->children()[0];
+  // As test_layer doesn't draw content, the layer list of root's render surface
+  // should contain only the root layer.
+  ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+  ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+
+  // Hit testing for a point outside the test layer should return null pointer.
+  // We also implicitly check that the updated screen space transform of a layer
+  // that is not in drawn render surface layer list (test_layer) is used during
+  // hit testing (becuase the point is inside test_layer with respect to the old
+  // screen space transform).
+  gfx::PointF test_point(24.f, 24.f);
+  test_layer->SetPosition(gfx::PointF(25.f, 25.f));
+  gfx::Transform expected_screen_space_transform;
+  expected_screen_space_transform.Translate(25.f, 25.f);
+
+  host_impl().active_tree()->property_trees()->needs_rebuild = true;
+  host_impl().active_tree()->BuildPropertyTreesForTesting();
+  LayerImpl* result_layer =
+      host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+          test_point);
+  EXPECT_FALSE(result_layer);
+  EXPECT_FALSE(test_layer->IsDrawnRenderSurfaceLayerListMember());
+  EXPECT_TRANSFORMATION_MATRIX_EQ(expected_screen_space_transform,
+                                  test_layer->screen_space_transform());
+
+  // We change the position of the test layer such that the test point is now
+  // inside the test_layer.
+  test_layer = host_impl().active_tree()->root_layer()->children()[0];
+  test_layer->SetPosition(gfx::PointF(10.f, 10.f));
+  expected_screen_space_transform.MakeIdentity();
+  expected_screen_space_transform.Translate(10.f, 10.f);
+
+  host_impl().active_tree()->property_trees()->needs_rebuild = true;
+  host_impl().active_tree()->BuildPropertyTreesForTesting();
+  result_layer =
+      host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+          test_point);
+  ASSERT_TRUE(result_layer);
+  ASSERT_EQ(test_layer, result_layer);
+  EXPECT_FALSE(result_layer->IsDrawnRenderSurfaceLayerListMember());
+  EXPECT_TRANSFORMATION_MATRIX_EQ(expected_screen_space_transform,
+                                  result_layer->screen_space_transform());
+}
+
 TEST_F(LayerTreeImplTest, SelectionBoundsForSingleLayer) {
   int root_layer_id = 12345;
   scoped_ptr<LayerImpl> root =
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 02baea8..7525c59 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -403,6 +403,12 @@
             android:process=":browser_restart_process">
         </activity>
 
+        <!-- Activity to list Physical Web Urls -->
+        <activity android:name="org.chromium.chrome.browser.physicalweb.ListUrlsActivity"
+            android:label="@string/physical_web_list_urls_activity_title"
+            android:exported="false">
+        </activity>
+
         <!-- Providers for chrome data. -->
         <provider android:name="org.chromium.chrome.browser.ChromeBrowserProvider"
             android:authorities="{{ manifest_package }}.ChromeBrowserProvider;{{ manifest_package }}.browser;{{ manifest_package }}"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
index 5d5a421..8ca7b2e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
@@ -165,7 +165,6 @@
             destroyContentView();
         }
 
-        System.out.println("ctxs --- OverlayPanelContent.createNewContentView");
         mContentViewCore = new ContentViewCore(mActivity);
 
         if (mContentViewClient == null) {
@@ -227,7 +226,6 @@
      */
     private void destroyContentView() {
         if (mContentViewCore != null) {
-            System.out.println("ctxs --- OverlayPanelContent.destroyContentView");
             nativeDestroyWebContents(mNativeOverlayPanelContentPtr);
             mContentViewCore.getWebContents().destroy();
             mContentViewCore.destroy();
@@ -260,7 +258,6 @@
      * @param url The URL that should be loaded.
      */
     public void loadUrl(String url) {
-        System.out.println("ctxs --- OverlayPanelContent.loadUrl");
         createNewContentView();
 
         if (mContentViewCore != null && mContentViewCore.getWebContents() != null) {
@@ -342,7 +339,6 @@
             // your Web History (if enabled). For this reason, onShow() should only be called
             // when we know for sure the page will be seen by the user.
             if (mContentViewCore != null) mContentViewCore.onShow();
-            if (mContentViewCore != null) System.out.println("ctxs --- mContentViewCore.onShow");
 
             mContentDelegate.onContentViewSeen();
         } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java
index 8c3a49e..2b2cda51 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java
@@ -29,6 +29,7 @@
 import org.chromium.chrome.browser.infobar.ConfirmInfoBar;
 import org.chromium.chrome.browser.infobar.InfoBar;
 import org.chromium.chrome.browser.infobar.InfoBarListeners;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.content.browser.ContentViewDownloadDelegate;
@@ -56,14 +57,17 @@
 
     // The application context.
     private final Context mContext;
-    private final Tab mTab;
+    private Tab mTab;
     private final TabModelSelector mTabModelSelector;
 
     // Pending download request for a dangerous file.
     private DownloadInfo mPendingRequest;
 
+    private final EmptyTabObserver mTabObserver;
+
     @Override
     public void onConfirmInfoBarButtonClicked(ConfirmInfoBar infoBar, boolean confirm) {
+        assert mTab != null;
         if (mPendingRequest.hasDownloadId()) {
             nativeDangerousDownloadValidated(mTab, mPendingRequest.getDownloadId(), confirm);
             if (confirm) {
@@ -115,6 +119,7 @@
     public void onInfoBarDismissed(InfoBar infoBar) {
         if (mPendingRequest != null) {
             if (mPendingRequest.hasDownloadId()) {
+                assert mTab != null;
                 nativeDangerousDownloadValidated(mTab, mPendingRequest.getDownloadId(), false);
             } else if (!mPendingRequest.isGETRequest()) {
                 // Infobar was dismissed, discard the file if a POST download is pending.
@@ -135,6 +140,12 @@
             Context context, TabModelSelector tabModelSelector, Tab tab) {
         mContext = context;
         mTab = tab;
+        mTabObserver = new EmptyTabObserver() {
+            @Override
+            public void onDestroyed(Tab tab) {
+                mTab = null;
+            }
+        };
         mTabModelSelector = tabModelSelector;
         mPendingRequest = null;
     }
@@ -289,6 +300,8 @@
     private void confirmDangerousDownload(DownloadInfo downloadInfo) {
         // A Dangerous file is already pending user confirmation, ignore the new download.
         if (mPendingRequest != null) return;
+        // Tab is already destroyed, no need to add an infobar.
+        if (mTab == null) return;
 
         mPendingRequest = downloadInfo;
 
@@ -297,7 +310,6 @@
         final String titleText = nativeGetDownloadWarningText(mPendingRequest.getFileName());
         final String okButtonText = mContext.getResources().getString(R.string.ok);
         final String cancelButtonText = mContext.getResources().getString(R.string.cancel);
-
         mTab.getInfoBarContainer().addInfoBar(new ConfirmInfoBar(
                 this, drawableId, null, titleText, null, okButtonText, cancelButtonText));
     }
@@ -320,6 +332,11 @@
 
     @Override
     public void requestFileAccess(final long callbackId) {
+        if (mTab == null) {
+            // TODO(tedchoc): Show toast (only when activity is alive).
+            DownloadController.getInstance().onRequestFileAccessResult(callbackId, false);
+            return;
+        }
         final String storagePermission = android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
         final Activity activity = mTab.getWindowAndroid().getActivity().get();
 
@@ -431,6 +448,7 @@
     }
 
     private void launchDownloadInfoBar(DownloadInfo info, String dirName, String fullDirPath) {
+        if (mTab == null) return;
         nativeLaunchDownloadOverwriteInfoBar(
                 ChromeDownloadDelegate.this, mTab, info, info.getFileName(), dirName, fullDirPath);
     }
@@ -584,9 +602,13 @@
 
     /**
      * Close a blank tab just opened for the download purpose.
-     * @return true iff the tab was closed.
+     * @return true iff the tab was (already) closed.
      */
     private boolean closeBlankTab() {
+        if (mTab == null) {
+            // We do not want caller to dismiss infobar.
+            return true;
+        }
         WebContents contents = mTab.getWebContents();
         boolean isInitialNavigation = contents == null
                 || contents.getNavigationController().isInitialNavigation();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
index dd93ae8..26ec9c4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
@@ -45,8 +45,6 @@
     protected static final String TAG = "FirstRunActivity";
 
     // Incoming parameters:
-    public static final String ORIGINAL_INTENT = "OriginalIntent";
-    public static final String FIRE_ORIGINAL_INTENT = "FireOriginalIntent";
     public static final String COMING_FROM_CHROME_ICON = "ComingFromChromeIcon";
     public static final String USE_FRE_FLOW_SEQUENCER = "UseFreFlowSequencer";
 
@@ -292,11 +290,6 @@
         mFreProperties.putBoolean(RESULT_SHOW_SYNC_SETTINGS, mResultShowSyncSettings);
         FirstRunFlowSequencer.markFlowAsCompleted(this, mFreProperties);
 
-        if (mFreProperties.getBoolean(FirstRunActivity.FIRE_ORIGINAL_INTENT)) {
-            Intent originalIntent = mFreProperties.getParcelable(FirstRunActivity.ORIGINAL_INTENT);
-            startActivity(originalIntent);
-        }
-
         if (DataReductionPromoScreen
                 .getDisplayedDataReductionPromo(getApplicationContext())) {
             if (DataReductionProxySettings.getInstance().isDataReductionProxyEnabled()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
index b3353c7..c286e3b4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
@@ -198,7 +198,7 @@
     /**
      * Checks if the First Run needs to be launched.
      * @return The intent to launch the First Run Experience if necessary, or null.
-     * @param activity       The context
+     * @param context The context
      * @param fromChromeIcon Whether Chrome is opened via the Chrome icon
      */
     public static Intent checkIfFirstRunIsNecessary(Context context, boolean fromChromeIcon) {
@@ -224,7 +224,7 @@
 
     /**
      * @return A generic intent to show the First Run Activity.
-     * @param context        The context
+     * @param context The context
      * @param fromChromeIcon Whether Chrome is opened via the Chrome icon
     */
     public static Intent createGenericFirstRunIntent(Context context, boolean fromChromeIcon) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
new file mode 100644
index 0000000..5ecbc0ae
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
@@ -0,0 +1,52 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.physicalweb;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+/**
+ * This activity displays a list of nearby URLs as stored in the {@link UrlManager}.
+ * This activity does not and should not rely directly or indirectly on the native library.
+ */
+public class ListUrlsActivity extends ListActivity {
+    private static final String TAG = "PhysicalWeb";
+    private ArrayAdapter<String> mAdapter;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
+        setListAdapter(mAdapter);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mAdapter.clear();
+        mAdapter.addAll(UrlManager.getInstance(this).getUrls());
+    }
+
+    /**
+     * Handle a click event.
+     * @param l The ListView.
+     * @param v The View that was clicked inside the ListView.
+     * @param position The position of the clicked element in the list.
+     * @param id The row id of the clicked element in the list.
+     */
+    @Override
+    public void onListItemClick(ListView l, View v, int position, long id) {
+        String url = mAdapter.getItem(position);
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.setData(Uri.parse(url));
+        startActivity(intent);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
index 30c093ff..87becc1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
@@ -5,7 +5,9 @@
 package org.chromium.chrome.browser.physicalweb;
 
 import android.app.Notification;
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.support.v4.app.NotificationCompat;
@@ -75,6 +77,13 @@
         updateNotification(urls);
     }
 
+    /**
+     * Get the stored URLs.
+     */
+    public Set<String> getUrls() {
+        return getCachedUrls();
+    }
+
     private Set<String> getCachedUrls() {
         // Check the version.
         SharedPreferences prefs = mContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
@@ -98,6 +107,12 @@
         editor.apply();
     }
 
+    private PendingIntent createListUrlsIntent() {
+        Intent intent = new Intent(mContext, ListUrlsActivity.class);
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+        return pendingIntent;
+    }
+
     private void updateNotification(Set<String> urls) {
         if (urls.isEmpty()) {
             mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_PHYSICAL_WEB);
@@ -109,12 +124,14 @@
         Resources resources = mContext.getResources();
         String title = resources.getQuantityString(R.plurals.physical_web_notification_title,
                                                    urls.size(), urls.size());
+        PendingIntent pendingIntent = createListUrlsIntent();
 
         // Create the notification.
         Notification notification = new NotificationCompat.Builder(mContext)
                 .setSmallIcon(R.drawable.ic_physical_web_notification)
                 .setContentTitle(title)
                 .setContentText(displayUrl)
+                .setContentIntent(pendingIntent)
                 .setPriority(NotificationCompat.PRIORITY_MIN)
                 .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                 .build();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java
index 6c7914c..aa9c2162 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java
@@ -130,6 +130,7 @@
 
     private static class ToolbarViewResourceAdapter extends ViewResourceAdapter {
         private final int mToolbarActualHeightPx;
+        private final int mTabStripHeightPx;
         private final int[] mTempPosition = new int[2];
 
         private final View mToolbarContainer;
@@ -147,6 +148,8 @@
             }
             mToolbarActualHeightPx = toolbarContainer.getResources().getDimensionPixelSize(
                     containerHeightResId);
+            mTabStripHeightPx = toolbarContainer.getResources().getDimensionPixelSize(
+                    R.dimen.tab_strip_height);
         }
 
         /**
@@ -186,7 +189,7 @@
 
         @Override
         protected void computeContentPadding(Rect outContentPadding) {
-            outContentPadding.set(0, ((View) mToolbar).getTop(), mToolbarContainer.getWidth(),
+            outContentPadding.set(0, mTabStripHeightPx, mToolbarContainer.getWidth(),
                     mToolbarActualHeightPx);
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
index 22bada4a..264d041 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -35,7 +35,6 @@
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.content.browser.ScreenOrientationProvider;
 import org.chromium.content_public.browser.LoadUrlParams;
-import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.net.NetworkChangeNotifier;
 import org.chromium.ui.base.PageTransition;
 
@@ -55,8 +54,6 @@
 
     private boolean mOldWebappCleanupStarted;
 
-    private WebContentsObserver mWebContentsObserver;
-
     private ViewGroup mSplashScreen;
     private WebappUrlBar mUrlBar;
 
@@ -100,7 +97,6 @@
             if (NetworkChangeNotifier.isOnline()) getActivityTab().reloadIgnoringCache();
         }
 
-        mWebContentsObserver = createWebContentsObserver();
         getActivityTab().addObserver(createTabObserver());
         getActivityTab().getTabWebContentsDelegateAndroid().setDisplayMode(
                 (int) WebDisplayMode.Standalone);
@@ -210,67 +206,6 @@
         mUrlBar.update(tab.getUrl(), tab.getSecurityLevel());
     }
 
-    private WebContentsObserver createWebContentsObserver() {
-        // TODO: Move to TabObserver eventually.
-        return new WebContentsObserver(getActivityTab().getWebContents()) {
-            @Override
-            public void didNavigateMainFrame(String url, String baseUrl,
-                    boolean isNavigationToDifferentPage, boolean isNavigationInPage,
-                    int statusCode) {
-                updateUrlBar();
-            }
-
-            @Override
-            public void didAttachInterstitialPage() {
-                updateUrlBar();
-
-                int state = ApplicationStatus.getStateForActivity(WebappActivity.this);
-                if (state == ActivityState.PAUSED || state == ActivityState.STOPPED
-                        || state == ActivityState.DESTROYED) {
-                    return;
-                }
-
-                // Kick the interstitial navigation to Chrome.
-                Intent intent = new Intent(
-                        Intent.ACTION_VIEW, Uri.parse(getActivityTab().getUrl()));
-                intent.setPackage(getPackageName());
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                startActivity(intent);
-
-                // Pretend like the navigation never happened.  We delay so that this happens while
-                // the Activity is in the background.
-                mHandler.postDelayed(new Runnable() {
-                    @Override
-                    public void run() {
-                        getActivityTab().goBack();
-                    }
-                }, MS_BEFORE_NAVIGATING_BACK_FROM_INTERSTITIAL);
-            }
-
-            @Override
-            public void didDetachInterstitialPage() {
-                updateUrlBar();
-            }
-
-            @Override
-            public void didFirstVisuallyNonEmptyPaint() {
-                if (mSplashScreen == null) return;
-
-                mSplashScreen.animate()
-                        .alpha(0f)
-                        .withEndAction(new Runnable() {
-                            @Override
-                            public void run() {
-                                ViewGroup contentView =
-                                        (ViewGroup) findViewById(android.R.id.content);
-                                contentView.removeView(mSplashScreen);
-                                mSplashScreen = null;
-                            }
-                        });
-            }
-        };
-    }
-
     private boolean isWebappDomain() {
         return UrlUtilities.sameDomainOrHost(
                 getActivityTab().getUrl(), getWebappInfo().uri().toString(), true);
@@ -308,6 +243,62 @@
                 if (!isWebappDomain()) return;
                 updateTaskDescription();
             }
+
+            @Override
+            public void onDidNavigateMainFrame(Tab tab, String url, String baseUrl,
+                    boolean isNavigationToDifferentPage, boolean isNavigationInPage,
+                    int statusCode) {
+                updateUrlBar();
+            }
+
+            @Override
+            public void onDidAttachInterstitialPage(Tab tab) {
+                updateUrlBar();
+
+                int state = ApplicationStatus.getStateForActivity(WebappActivity.this);
+                if (state == ActivityState.PAUSED || state == ActivityState.STOPPED
+                        || state == ActivityState.DESTROYED) {
+                    return;
+                }
+
+                // Kick the interstitial navigation to Chrome.
+                Intent intent = new Intent(
+                        Intent.ACTION_VIEW, Uri.parse(getActivityTab().getUrl()));
+                intent.setPackage(getPackageName());
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                startActivity(intent);
+
+                // Pretend like the navigation never happened.  We delay so that this happens while
+                // the Activity is in the background.
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        getActivityTab().goBack();
+                    }
+                }, MS_BEFORE_NAVIGATING_BACK_FROM_INTERSTITIAL);
+            }
+
+            @Override
+            public void onDidDetachInterstitialPage(Tab tab) {
+                updateUrlBar();
+            }
+
+            @Override
+            public void didFirstVisuallyNonEmptyPaint(Tab tab) {
+                if (mSplashScreen == null) return;
+
+                mSplashScreen.animate()
+                        .alpha(0f)
+                        .withEndAction(new Runnable() {
+                            @Override
+                            public void run() {
+                                ViewGroup contentView =
+                                        (ViewGroup) findViewById(android.R.id.content);
+                                contentView.removeView(mSplashScreen);
+                                mSplashScreen = null;
+                            }
+                        });
+            }
         };
     }
 
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 54141b6..2463566 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2277,6 +2277,9 @@
       </message>
 
       <!-- Physical Web strings -->
+      <message name="IDS_PHYSICAL_WEB_LIST_URLS_ACTIVITY_TITLE" desc="The title for a dialog that shows a list of URLs broadcasted from nearby devices.">
+        Nearby URLs
+      </message>
       <message name="IDS_PHYSICAL_WEB_NOTIFICATION_TITLE" desc="Description of quantity of discovered URLs nearby.">
         {NUM_URLS, plural,
          =1 {1 URL nearby}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index b6e145e..5a6dbe6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -792,6 +792,7 @@
      * Tests a sequence in landscape orientation: swiping the overlay open, after an
      * initial tap that activates the peeking card.
      */
+    @DisabledTest // https://crbug.com/543733
     @SmallTest
     @Feature({"ContextualSearch"})
     @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index e4478cc8..08593186 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -110,6 +110,7 @@
     "//components/content_settings/content/common",
     "//components/content_settings/core/browser",
     "//components/content_settings/core/common",
+    "//components/cookie_config",
     "//components/crx_file",
     "//components/data_reduction_proxy/core/browser",
     "//components/data_usage/core",
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index 1cd1713d..9fd082e 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -146,6 +146,7 @@
 #if defined(ENABLE_TOPCHROME_MD)
     ::switches::kTopChromeMD,
 #endif
+    ::switches::kUIDisablePartialSwap,
     ::switches::kUIEnableCompositorAnimationTimelines,
     ::switches::kUIPrioritizeInGpuProcess,
 #if defined(USE_CRAS)
@@ -185,6 +186,7 @@
     // Please keep these in alphabetical order. Non-UI Compositor switches
     // here should also be added to
     // content/browser/renderer_host/render_process_host_impl.cc.
+    cc::switches::kDisableCachedPictureRaster,
     cc::switches::kDisableCompositedAntialiasing,
     cc::switches::kDisableMainFrameBeforeActivation,
     cc::switches::kDisableThreadedAnimation,
@@ -200,7 +202,6 @@
     cc::switches::kShowScreenSpaceRects,
     cc::switches::kShowSurfaceDamageRects,
     cc::switches::kSlowDownRasterScaleFactor,
-    cc::switches::kUIDisablePartialSwap,
     chromeos::switches::kConsumerDeviceManagementUrl,
     chromeos::switches::kDbusStub,
     chromeos::switches::kDbusUnstubClients,
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index db81dee..abae1f8 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/menu_manager.h"
+#include "chrome/browser/extensions/updater/chrome_update_client_config.h"
 #include "chrome/browser/external_protocol/external_protocol_handler.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -36,6 +37,7 @@
 #include "chrome/common/extensions/features/feature_channel.h"
 #include "chrome/common/pref_names.h"
 #include "components/net_log/chrome_net_log.h"
+#include "components/update_client/update_client.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/content_switches.h"
@@ -380,4 +382,11 @@
   }
 }
 
+scoped_refptr<update_client::UpdateClient>
+ChromeExtensionsBrowserClient::CreateUpdateClient(
+    content::BrowserContext* context) {
+  return update_client::UpdateClientFactory(
+      make_scoped_refptr(new ChromeUpdateClientConfig(context)));
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.h b/chrome/browser/extensions/chrome_extensions_browser_client.h
index c9d41a34..4633436 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.h
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.h
@@ -5,11 +5,13 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSIONS_BROWSER_CLIENT_H_
 #define CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSIONS_BROWSER_CLIENT_H_
 
-#include <map>
+#include <string>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/lazy_instance.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/chrome_notification_observer.h"
 #include "extensions/browser/extensions_browser_client.h"
@@ -111,6 +113,8 @@
                       int view_instance_id) override;
   void AttachExtensionTaskManagerTag(content::WebContents* web_contents,
                                      ViewType view_type) override;
+  scoped_refptr<update_client::UpdateClient> CreateUpdateClient(
+      content::BrowserContext* context) override;
 
  private:
   friend struct base::DefaultLazyInstanceTraits<ChromeExtensionsBrowserClient>;
diff --git a/chrome/browser/extensions/extension_system_impl.cc b/chrome/browser/extensions/extension_system_impl.cc
index bbf1452..836c829 100644
--- a/chrome/browser/extensions/extension_system_impl.cc
+++ b/chrome/browser/extensions/extension_system_impl.cc
@@ -8,6 +8,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_tokenizer.h"
 #include "base/trace_event/trace_event.h"
@@ -374,6 +375,12 @@
       extension);
 }
 
+void ExtensionSystemImpl::InstallUpdate(const std::string& extension_id,
+                                        const base::FilePath& temp_dir) {
+  NOTREACHED() << "Not yet implemented";
+  base::DeleteFile(temp_dir, true /* recursive */);
+}
+
 void ExtensionSystemImpl::RegisterExtensionWithRequestContexts(
     const Extension* extension,
     const base::Closure& callback) {
diff --git a/chrome/browser/extensions/extension_system_impl.h b/chrome/browser/extensions/extension_system_impl.h
index 49369ff8..0ad93570 100644
--- a/chrome/browser/extensions/extension_system_impl.h
+++ b/chrome/browser/extensions/extension_system_impl.h
@@ -54,6 +54,8 @@
   ContentVerifier* content_verifier() override;  // shared
   scoped_ptr<ExtensionSet> GetDependentExtensions(
       const Extension* extension) override;
+  void InstallUpdate(const std::string& extension_id,
+                     const base::FilePath& temp_dir) override;
 
  private:
   friend class ExtensionSystemSharedFactory;
diff --git a/chrome/browser/extensions/test_extension_system.cc b/chrome/browser/extensions/test_extension_system.cc
index ad06d0c..5801ae7d 100644
--- a/chrome/browser/extensions/test_extension_system.cc
+++ b/chrome/browser/extensions/test_extension_system.cc
@@ -127,6 +127,11 @@
       extension);
 }
 
+void TestExtensionSystem::InstallUpdate(const std::string& extension_id,
+                                        const base::FilePath& temp_dir) {
+  NOTREACHED();
+}
+
 // static
 scoped_ptr<KeyedService> TestExtensionSystem::Build(
     content::BrowserContext* profile) {
diff --git a/chrome/browser/extensions/test_extension_system.h b/chrome/browser/extensions/test_extension_system.h
index d0c11e4a..9e85ec4 100644
--- a/chrome/browser/extensions/test_extension_system.h
+++ b/chrome/browser/extensions/test_extension_system.h
@@ -58,6 +58,8 @@
   ContentVerifier* content_verifier() override;
   scoped_ptr<ExtensionSet> GetDependentExtensions(
       const Extension* extension) override;
+  void InstallUpdate(const std::string& extension_id,
+                     const base::FilePath& temp_dir) override;
 
   // Note that you probably want to use base::RunLoop().RunUntilIdle() right
   // after this to run all the accumulated tasks.
diff --git a/chrome/browser/extensions/updater/chrome_update_client_config.cc b/chrome/browser/extensions/updater/chrome_update_client_config.cc
new file mode 100644
index 0000000..1c095f7d
--- /dev/null
+++ b/chrome/browser/extensions/updater/chrome_update_client_config.cc
@@ -0,0 +1,89 @@
+// 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 "base/command_line.h"
+#include "base/version.h"
+#include "chrome/browser/component_updater/component_patcher_operation_out_of_process.h"
+#include "chrome/browser/extensions/updater/chrome_update_client_config.h"
+#include "chrome/browser/update_client/chrome_update_query_params_delegate.h"
+#include "chrome/common/channel_info.h"
+#include "content/public/browser/browser_context.h"
+
+namespace extensions {
+
+ChromeUpdateClientConfig::ChromeUpdateClientConfig(
+    content::BrowserContext* context)
+    : impl_(base::CommandLine::ForCurrentProcess(),
+            context->GetRequestContext()) {
+  impl_.set_enable_alt_source_url(false);
+}
+
+int ChromeUpdateClientConfig::InitialDelay() const {
+  return impl_.InitialDelay();
+}
+
+int ChromeUpdateClientConfig::NextCheckDelay() const {
+  return impl_.NextCheckDelay();
+}
+
+int ChromeUpdateClientConfig::StepDelay() const {
+  return impl_.StepDelay();
+}
+
+int ChromeUpdateClientConfig::OnDemandDelay() const {
+  return impl_.OnDemandDelay();
+}
+
+int ChromeUpdateClientConfig::UpdateDelay() const {
+  return 0;
+}
+
+std::vector<GURL> ChromeUpdateClientConfig::UpdateUrl() const {
+  return impl_.UpdateUrl();
+}
+
+std::vector<GURL> ChromeUpdateClientConfig::PingUrl() const {
+  return impl_.PingUrl();
+}
+
+base::Version ChromeUpdateClientConfig::GetBrowserVersion() const {
+  return impl_.GetBrowserVersion();
+}
+
+std::string ChromeUpdateClientConfig::GetChannel() const {
+  return chrome::GetChannelString();
+}
+
+std::string ChromeUpdateClientConfig::GetLang() const {
+  return ChromeUpdateQueryParamsDelegate::GetLang();
+}
+
+std::string ChromeUpdateClientConfig::GetOSLongName() const {
+  return impl_.GetOSLongName();
+}
+
+std::string ChromeUpdateClientConfig::ExtraRequestParams() const {
+  return impl_.ExtraRequestParams();
+}
+
+net::URLRequestContextGetter* ChromeUpdateClientConfig::RequestContext() const {
+  return impl_.RequestContext();
+}
+
+scoped_refptr<update_client::OutOfProcessPatcher>
+ChromeUpdateClientConfig::CreateOutOfProcessPatcher() const {
+  return make_scoped_refptr(new component_updater::ChromeOutOfProcessPatcher);
+}
+
+bool ChromeUpdateClientConfig::DeltasEnabled() const {
+  return impl_.DeltasEnabled();
+}
+
+bool ChromeUpdateClientConfig::UseBackgroundDownloader() const {
+  return impl_.UseBackgroundDownloader();
+}
+
+ChromeUpdateClientConfig::~ChromeUpdateClientConfig() {}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/updater/chrome_update_client_config.h b/chrome/browser/extensions/updater/chrome_update_client_config.h
new file mode 100644
index 0000000..1e6cab6
--- /dev/null
+++ b/chrome/browser/extensions/updater/chrome_update_client_config.h
@@ -0,0 +1,55 @@
+// 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_EXTENSIONS_UPDATER_CHROME_UPDATE_CLIENT_CONFIG_H_
+#define CHROME_BROWSER_EXTENSIONS_UPDATER_CHROME_UPDATE_CLIENT_CONFIG_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "components/component_updater/configurator_impl.h"
+#include "extensions/browser/updater/update_client_config.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace extensions {
+
+class ChromeUpdateClientConfig : public UpdateClientConfig {
+ public:
+  explicit ChromeUpdateClientConfig(content::BrowserContext* context);
+
+  int InitialDelay() const override;
+  int NextCheckDelay() const override;
+  int StepDelay() const override;
+  int OnDemandDelay() const override;
+  int UpdateDelay() const override;
+  std::vector<GURL> UpdateUrl() const override;
+  std::vector<GURL> PingUrl() const override;
+  base::Version GetBrowserVersion() const override;
+  std::string GetChannel() const override;
+  std::string GetLang() const override;
+  std::string GetOSLongName() const override;
+  std::string ExtraRequestParams() const override;
+  net::URLRequestContextGetter* RequestContext() const override;
+  scoped_refptr<update_client::OutOfProcessPatcher> CreateOutOfProcessPatcher()
+      const override;
+  bool DeltasEnabled() const override;
+  bool UseBackgroundDownloader() const override;
+
+ protected:
+  friend class base::RefCountedThreadSafe<ChromeUpdateClientConfig>;
+  ~ChromeUpdateClientConfig() override;
+
+ private:
+  component_updater::ConfiguratorImpl impl_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeUpdateClientConfig);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_UPDATER_CHROME_UPDATE_CLIENT_CONFIG_H_
diff --git a/chrome/browser/google/google_update_win.cc b/chrome/browser/google/google_update_win.cc
index 7980192..97d354a 100644
--- a/chrome/browser/google/google_update_win.cc
+++ b/chrome/browser/google/google_update_win.cc
@@ -7,6 +7,8 @@
 #include <atlbase.h>
 #include <atlcom.h>
 
+#include <vector>
+
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/files/file_path.h"
@@ -206,8 +208,7 @@
       gfx::AcceleratedWidget elevation_window,
       const base::WeakPtr<UpdateCheckDelegate>& delegate);
 
-  // Invokes a completion or error method on the caller's delegate, as
-  // appropriate.
+  // Invokes a completion or error method on all delegates, as appropriate.
   ~UpdateCheckDriver();
 
   // Starts an update check.
@@ -221,7 +222,7 @@
   // |hresult|, installer_exit_code_ to |installer_exit_code|, and
   // html_error_message_ to a composition of all values suitable for display
   // to the user. This call should be followed by deletion of the driver,
-  // which will result in the caller being notified via its delegate.
+  // which will result in callers being notified via their delegates.
   void OnUpgradeError(GoogleUpdateErrorCode error_code,
                       HRESULT hresult,
                       int installer_exit_code,
@@ -283,10 +284,17 @@
   // previous notification) and another future poll will be scheduled.
   void PollGoogleUpdate();
 
+  // If an UpdateCheckDriver is already running, the delegate is added to the
+  // existing one instead of creating a new one.
+  void AddDelegate(const base::WeakPtr<UpdateCheckDelegate>& delegate);
+
+  static UpdateCheckDriver* driver_;
+
   // The task runner on which the update checks runs.
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
-  // The caller's task runner, on which methods of |delegate_| will be invoked.
+  // The caller's task runner, on which methods of the |delegates_| will be
+  // invoked.
   scoped_refptr<base::SingleThreadTaskRunner> result_runner_;
 
   // The UI locale.
@@ -298,8 +306,8 @@
   // A parent window in case any UX is required (e.g., an elevation prompt).
   gfx::AcceleratedWidget elevation_window_;
 
-  // The caller's delegate by which feedback is conveyed.
-  base::WeakPtr<UpdateCheckDelegate> delegate_;
+  // Contains all delegates by which feedback is conveyed.
+  std::vector<base::WeakPtr<UpdateCheckDelegate>> delegates_;
 
   // Number of remaining retries allowed when errors occur.
   int allowed_retries_;
@@ -331,6 +339,8 @@
   DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver);
 };
 
+UpdateCheckDriver* UpdateCheckDriver::driver_ = nullptr;
+
 // static
 void UpdateCheckDriver::RunUpdateCheck(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
@@ -338,14 +348,21 @@
     bool install_update_if_possible,
     gfx::AcceleratedWidget elevation_window,
     const base::WeakPtr<UpdateCheckDelegate>& delegate) {
-  // The driver is owned by itself, and will self-destruct when its work is
-  // done.
-  UpdateCheckDriver* driver =
-      new UpdateCheckDriver(task_runner, locale, install_update_if_possible,
-                            elevation_window, delegate);
-  task_runner->PostTask(FROM_HERE,
-                        base::Bind(&UpdateCheckDriver::BeginUpdateCheck,
-                                   base::Unretained(driver)));
+  // Create the driver if it doesn't exist, or add the delegate to the existing
+  // one.
+  if (!driver_) {
+    // The driver is owned by itself, and will self-destruct when its work is
+    // done.
+    driver_ =
+        new UpdateCheckDriver(task_runner, locale, install_update_if_possible,
+                              elevation_window, delegate);
+    task_runner->PostTask(FROM_HERE,
+                          base::Bind(&UpdateCheckDriver::BeginUpdateCheck,
+                                     base::Unretained(driver_)));
+  } else {
+    DCHECK_EQ(driver_->task_runner_, task_runner);
+    driver_->AddDelegate(delegate);
+  }
 }
 
 // Runs on the caller's thread.
@@ -360,7 +377,6 @@
       locale_(locale),
       install_update_if_possible_(install_update_if_possible),
       elevation_window_(elevation_window),
-      delegate_(delegate),
       allowed_retries_(kGoogleAllowedRetries),
       system_level_install_(false),
       last_reported_progress_(0),
@@ -368,6 +384,7 @@
       error_code_(GOOGLE_UPDATE_NO_ERROR),
       hresult_(S_OK),
       installer_exit_code_(-1) {
+  delegates_.push_back(delegate);
 }
 
 UpdateCheckDriver::~UpdateCheckDriver() {
@@ -386,14 +403,18 @@
                                   installer_exit_code_);
     }
   }
-  if (delegate_) {
-    if (status_ == UPGRADE_ERROR)
-      delegate_->OnError(error_code_, html_error_message_, new_version_);
-    else if (install_update_if_possible_)
-      delegate_->OnUpgradeComplete(new_version_);
-    else
-      delegate_->OnUpdateCheckComplete(new_version_);
+  for (const auto& delegate : delegates_) {
+    if (delegate) {
+      if (status_ == UPGRADE_ERROR)
+        delegate->OnError(error_code_, html_error_message_, new_version_);
+      else if (install_update_if_possible_)
+        delegate->OnUpgradeComplete(new_version_);
+      else
+        delegate->OnUpdateCheckComplete(new_version_);
+    }
   }
+
+  driver_ = nullptr;
 }
 
 void UpdateCheckDriver::BeginUpdateCheck() {
@@ -710,10 +731,12 @@
 
       // It is safe to post this task with an unretained pointer since the task
       // is guaranteed to run before a subsequent DeleteSoon is handled.
-      result_runner_->PostTask(
-          FROM_HERE,
-          base::Bind(&UpdateCheckDelegate::OnUpgradeProgress, delegate_,
-                     last_reported_progress_, new_version_));
+      for (const auto& delegate : delegates_) {
+        result_runner_->PostTask(
+            FROM_HERE,
+            base::Bind(&UpdateCheckDelegate::OnUpgradeProgress, delegate,
+                       last_reported_progress_, new_version_));
+      }
     }
 
     // Schedule the next check.
@@ -735,6 +758,11 @@
   result_runner_->DeleteSoon(FROM_HERE, this);
 }
 
+void UpdateCheckDriver::AddDelegate(
+    const base::WeakPtr<UpdateCheckDelegate>& delegate) {
+  delegates_.push_back(delegate);
+}
+
 void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code,
                                        HRESULT hresult,
                                        int installer_exit_code,
diff --git a/chrome/browser/google/google_update_win_unittest.cc b/chrome/browser/google/google_update_win_unittest.cc
index d7d89629..700c10c 100644
--- a/chrome/browser/google/google_update_win_unittest.cc
+++ b/chrome/browser/google/google_update_win_unittest.cc
@@ -952,6 +952,68 @@
   task_runner_->RunUntilIdle();
 }
 
+TEST_P(GoogleUpdateWinTest, UpdateInstalledMultipleDelegates) {
+  CComObject<MockAppBundle>* mock_app_bundle = nullptr;
+  CComObject<MockApp>* mock_app = nullptr;
+  MakeGoogleUpdateMocks(&mock_app_bundle, &mock_app);
+
+  // Expect the bundle to be called on to start the update.
+  EXPECT_CALL(*mock_app_bundle, checkForUpdate()).WillOnce(Return(S_OK));
+  // Expect the bundle to be called on to start the install.
+  EXPECT_CALL(*mock_app_bundle, install()).WillOnce(Return(S_OK));
+
+  mock_app->PushState(STATE_INIT);
+  mock_app->PushState(STATE_CHECKING_FOR_UPDATE);
+  mock_app->PushUpdateAvailableState(new_version_);
+  mock_app->PushState(STATE_WAITING_TO_DOWNLOAD);
+  mock_app->PushProgressiveState(STATE_DOWNLOADING, 0);
+  mock_app->PushProgressiveState(STATE_DOWNLOADING, 25);
+  mock_app->PushProgressiveState(STATE_DOWNLOADING, 25);
+  mock_app->PushProgressiveState(STATE_DOWNLOADING, 75);
+  mock_app->PushState(STATE_WAITING_TO_INSTALL);
+  mock_app->PushProgressiveState(STATE_INSTALLING, 50);
+  mock_app->PushState(STATE_INSTALL_COMPLETE);
+
+  StrictMock<MockUpdateCheckDelegate> mock_update_check_delegate_2;
+  {
+    InSequence callback_sequence;
+    EXPECT_CALL(mock_update_check_delegate_,
+                OnUpgradeProgress(0, StrEq(new_version_)));
+    EXPECT_CALL(mock_update_check_delegate_2,
+                OnUpgradeProgress(0, StrEq(new_version_)));
+
+    EXPECT_CALL(mock_update_check_delegate_,
+                OnUpgradeProgress(12, StrEq(new_version_)));
+    EXPECT_CALL(mock_update_check_delegate_2,
+                OnUpgradeProgress(12, StrEq(new_version_)));
+
+    EXPECT_CALL(mock_update_check_delegate_,
+                OnUpgradeProgress(37, StrEq(new_version_)));
+    EXPECT_CALL(mock_update_check_delegate_2,
+                OnUpgradeProgress(37, StrEq(new_version_)));
+
+    EXPECT_CALL(mock_update_check_delegate_,
+                OnUpgradeProgress(50, StrEq(new_version_)));
+    EXPECT_CALL(mock_update_check_delegate_2,
+                OnUpgradeProgress(50, StrEq(new_version_)));
+
+    EXPECT_CALL(mock_update_check_delegate_,
+                OnUpgradeProgress(75, StrEq(new_version_)));
+    EXPECT_CALL(mock_update_check_delegate_2,
+                OnUpgradeProgress(75, StrEq(new_version_)));
+
+    EXPECT_CALL(mock_update_check_delegate_,
+                OnUpgradeComplete(StrEq(new_version_)));
+    EXPECT_CALL(mock_update_check_delegate_2,
+                OnUpgradeComplete(StrEq(new_version_)));
+  }
+  BeginUpdateCheck(task_runner_, std::string(), true, 0,
+                   mock_update_check_delegate_.AsWeakPtr());
+  BeginUpdateCheck(task_runner_, std::string(), true, 0,
+                   mock_update_check_delegate_2.AsWeakPtr());
+  task_runner_->RunUntilIdle();
+}
+
 INSTANTIATE_TEST_CASE_P(UserLevel, GoogleUpdateWinTest, Values(false));
 
 INSTANTIATE_TEST_CASE_P(SystemLevel, GoogleUpdateWinTest, Values(true));
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index 244f62f9..433978a0 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -28,7 +28,6 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/crash_keys.h"
-#include "chrome/common/pref_names.h"
 #include "components/metrics/call_stack_profile_metrics_provider.h"
 #include "components/metrics/drive_metrics_provider.h"
 #include "components/metrics/gpu/gpu_metrics_provider.h"
@@ -168,9 +167,6 @@
 
 // static
 void ChromeMetricsServiceClient::RegisterPrefs(PrefRegistrySimple* registry) {
-  registry->RegisterInt64Pref(prefs::kUninstallLastLaunchTimeSec, 0);
-  registry->RegisterInt64Pref(prefs::kUninstallLastObservedRunTimeSec, 0);
-
   metrics::MetricsService::RegisterPrefs(registry);
   metrics::StabilityMetricsHelper::RegisterPrefs(registry);
 
diff --git a/chrome/browser/net/cookie_store_util.h b/chrome/browser/net/cookie_store_util.h
deleted file mode 100644
index c05391b..0000000
--- a/chrome/browser/net/cookie_store_util.h
+++ /dev/null
@@ -1,27 +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 CHROME_BROWSER_NET_COOKIE_STORE_UTIL_H_
-#define CHROME_BROWSER_NET_COOKIE_STORE_UTIL_H_
-
-#include "base/memory/ref_counted.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/cookie_store_factory.h"
-
-class Profile;
-
-namespace net {
-class CookieMonsterDelegate;
-}  // namespace net
-
-namespace chrome_browser_net {
-
-// Factory method for returning a CookieCryptoDelegate if one is appropriate for
-// this platform. The object returned is a LazyInstance. Ownership is not
-// transferred.
-net::CookieCryptoDelegate* GetCookieCryptoDelegate();
-
-}  // namespace chrome_browser_net
-
-#endif  // CHROME_BROWSER_NET_COOKIE_STORE_UTIL_H_
diff --git a/chrome/browser/net/net_error_tab_helper.cc b/chrome/browser/net/net_error_tab_helper.cc
index f0cbcf9..8e325f9b 100644
--- a/chrome/browser/net/net_error_tab_helper.cc
+++ b/chrome/browser/net/net_error_tab_helper.cc
@@ -18,14 +18,12 @@
 #include "components/error_page/common/net_error_info.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_view_host.h"
 #include "ipc/ipc_message_macros.h"
 #include "net/base/net_errors.h"
 #include "url/gurl.h"
 
 using content::BrowserContext;
 using content::BrowserThread;
-using content::RenderViewHost;
 using content::WebContents;
 using content::WebContentsObserver;
 using error_page::DnsProbeStatus;
@@ -82,13 +80,16 @@
   testing_state_ = state;
 }
 
-void NetErrorTabHelper::RenderViewCreated(
-    content::RenderViewHost* render_view_host) {
-  content::RenderFrameHost* render_frame_host =
-      render_view_host->GetMainFrame();
-  render_frame_host->Send(new ChromeViewMsg_SetCanShowNetworkDiagnosticsDialog(
-      render_frame_host->GetRoutingID(),
-      CanShowNetworkDiagnosticsDialog()));
+void NetErrorTabHelper::RenderFrameCreated(
+    content::RenderFrameHost* render_frame_host) {
+  // Ignore subframe creation - only main frame error pages can link to the
+  // platform's network diagnostics dialog.
+  if (render_frame_host->GetParent())
+    return;
+  render_frame_host->Send(
+      new ChromeViewMsg_SetCanShowNetworkDiagnosticsDialog(
+          render_frame_host->GetRoutingID(),
+          CanShowNetworkDiagnosticsDialog()));
 }
 
 void NetErrorTabHelper::DidStartNavigationToPendingEntry(
diff --git a/chrome/browser/net/net_error_tab_helper.h b/chrome/browser/net/net_error_tab_helper.h
index 490b432..4e6b83e 100644
--- a/chrome/browser/net/net_error_tab_helper.h
+++ b/chrome/browser/net/net_error_tab_helper.h
@@ -48,7 +48,7 @@
   }
 
   // content::WebContentsObserver implementation.
-  void RenderViewCreated(content::RenderViewHost* render_view_host) override;
+  void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
 
   void DidStartNavigationToPendingEntry(
       const GURL& url,
diff --git a/chrome/browser/profiles/DEPS b/chrome/browser/profiles/DEPS
index 3e4fe84..b6f5425f 100644
--- a/chrome/browser/profiles/DEPS
+++ b/chrome/browser/profiles/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+components/about_handler",
+  "+components/cookie_config",
   "+components/user_manager",
 ]
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index 0ad1af73..e0ca85f1 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -29,7 +29,6 @@
 #include "chrome/browser/io_thread.h"
 #include "chrome/browser/net/chrome_network_delegate.h"
 #include "chrome/browser/net/connect_interceptor.h"
-#include "chrome/browser/net/cookie_store_util.h"
 #include "chrome/browser/net/http_server_properties_manager_factory.h"
 #include "chrome/browser/net/predictor.h"
 #include "chrome/browser/net/quota_policy_channel_id_store.h"
@@ -41,6 +40,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
+#include "components/cookie_config/cookie_store_util.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
 #include "components/data_reduction_proxy/core/browser/data_store_impl.h"
@@ -513,8 +513,7 @@
         lazy_params_->session_cookie_mode,
         lazy_params_->special_storage_policy.get(),
         profile_params->cookie_monster_delegate.get());
-    cookie_config.crypto_delegate =
-      chrome_browser_net::GetCookieCryptoDelegate();
+    cookie_config.crypto_delegate = cookie_config::GetCookieCryptoDelegate();
     cookie_store = content::CreateCookieStore(cookie_config);
   }
 
@@ -616,8 +615,7 @@
       lazy_params_->extensions_cookie_path,
       lazy_params_->session_cookie_mode,
       NULL, NULL);
-  cookie_config.crypto_delegate =
-      chrome_browser_net::GetCookieCryptoDelegate();
+  cookie_config.crypto_delegate = cookie_config::GetCookieCryptoDelegate();
   net::CookieStore* extensions_cookie_store =
       content::CreateCookieStore(cookie_config);
   // Enable cookies for chrome-extension URLs.
@@ -694,8 +692,7 @@
         cookie_path,
         content::CookieStoreConfig::EPHEMERAL_SESSION_COOKIES,
         NULL, NULL);
-    cookie_config.crypto_delegate =
-      chrome_browser_net::GetCookieCryptoDelegate();
+    cookie_config.crypto_delegate = cookie_config::GetCookieCryptoDelegate();
     cookie_store = content::CreateCookieStore(cookie_config);
   }
 
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 52d9bc1..b43f827f 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -37,7 +37,6 @@
 #include "chrome/browser/net/chrome_http_user_agent_settings.h"
 #include "chrome/browser/net/chrome_network_delegate.h"
 #include "chrome/browser/net/chrome_url_request_context_getter.h"
-#include "chrome/browser/net/cookie_store_util.h"
 #include "chrome/browser/net/proxy_service_factory.h"
 #include "chrome/browser/net/resource_prefetch_predictor_observer.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
@@ -54,6 +53,7 @@
 #include "components/content_settings/core/browser/content_settings_provider.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/cookie_config/cookie_store_util.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
 #include "components/dom_distiller/core/url_constants.h"
 #include "components/metrics/metrics_pref_names.h"
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox.gni b/chrome/browser/resources/chromeos/chromevox/chromevox.gni
index 99c15e1..8d8ff392 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox.gni
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox.gni
@@ -128,6 +128,7 @@
   "cvox2/background/classic_compatibility.js",
   "cvox2/background/cursors.js",
   "cvox2/background/earcon_engine.js",
+  "cvox2/background/next_earcons.js",
   "cvox2/background/output.js",
   "extensions/searchvox/abstract_result.js",
   "extensions/searchvox/constants.js",
@@ -139,8 +140,8 @@
   "extensions/searchvox/util.js",
   "host/chrome/braille.js",
   "host/chrome/braille_background.js",
+  "host/chrome/classic_earcons.js",
   "host/chrome/earcons.js",
-  "host/chrome/earcons_background.js",
   "host/chrome/extension_bridge.js",
   "host/chrome/host.js",
   "host/chrome/mathjax.js",
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/background.js b/chrome/browser/resources/chromeos/chromevox/chromevox/background/background.js
index 9393c4a..4af0e42 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/background.js
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/background.js
@@ -15,9 +15,9 @@
 goog.require('cvox.ChromeVox');
 goog.require('cvox.ChromeVoxEditableTextBase');
 goog.require('cvox.ChromeVoxPrefs');
+goog.require('cvox.ClassicEarcons');
 goog.require('cvox.CompositeTts');
 goog.require('cvox.ConsoleTts');
-goog.require('cvox.EarconsBackground');
 goog.require('cvox.ExtensionBridge');
 goog.require('cvox.HostFactory');
 goog.require('cvox.InjectedScriptLoader');
@@ -75,7 +75,6 @@
       .add(this.backgroundTts_)
       .add(consoleTts);
 
-  this.earcons = new cvox.EarconsBackground();
   this.addBridgeListener();
 
   /**
@@ -85,13 +84,14 @@
    */
   this.backgroundBraille_ = new cvox.BrailleBackground();
 
-    this.tabsApiHandler_ = new cvox.TabsApiHandler(
-      this.tts, this.backgroundBraille_, this.earcons);
+  this.tabsApiHandler_ = new cvox.TabsApiHandler();
 
   // Export globals on cvox.ChromeVox.
   cvox.ChromeVox.tts = this.tts;
   cvox.ChromeVox.braille = this.backgroundBraille_;
-  cvox.ChromeVox.earcons = this.earcons;
+
+  if (!cvox.ChromeVox.earcons)
+    cvox.ChromeVox.earcons = new cvox.ClassicEarcons();
 
   if (cvox.ChromeVox.isChromeOS &&
       chrome.accessibilityPrivate.onIntroduceChromeVox) {
@@ -264,7 +264,7 @@
  */
 cvox.ChromeVoxBackground.prototype.onEarconMessage = function(msg) {
   if (msg.action == 'play') {
-    this.earcons.playEarcon(msg.earcon);
+    cvox.ChromeVox.earcons.playEarcon(msg.earcon);
   }
 };
 
@@ -328,7 +328,7 @@
                 false);
           }
         } else if (msg['pref'] == 'earcons') {
-          this.earcons.enabled = msg['value'];
+          cvox.AbstractEarcons.enabled = msg['value'];
         } else if (msg['pref'] == 'sticky' && msg['announce']) {
           if (msg['value']) {
             this.tts.speak(Msgs.getMsg('sticky_mode_enabled'),
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js b/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js
index 4719c15..b776438 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js
@@ -19,19 +19,8 @@
 /**
  * Class that adds listeners and handles events from the tabs API.
  * @constructor
- * @param {cvox.TtsInterface} tts The TTS to use for speaking.
- * @param {cvox.BrailleInterface} braille The braille interface to use for
- * brailling.
- * @param {cvox.AbstractEarcons} earcons The earcons object to use for playing
- *        earcons.
  */
-cvox.TabsApiHandler = function(tts, braille, earcons) {
-  /** @type {cvox.TtsInterface} @private */
-  this.tts_ = tts;
-  /** @type {cvox.BrailleInterface} @private */
-  this.braille_ = braille;
-  /** @type {cvox.AbstractEarcons} @private */
-  this.earcons_ = earcons;
+cvox.TabsApiHandler = function() {
   /** @type {function(string, Array<string>=)} @private */
   this.msg_ = Msgs.getMsg.bind(Msgs);
   /**
@@ -57,12 +46,12 @@
     if (!cvox.ChromeVox.isActive) {
       return;
     }
-    this.tts_.speak(this.msg_('chrome_tab_created'),
-                   cvox.QueueMode.FLUSH,
-                   cvox.AbstractTts.PERSONALITY_ANNOUNCEMENT);
-    this.braille_.write(
+    cvox.ChromeVox.tts.speak(this.msg_('chrome_tab_created'),
+                             cvox.QueueMode.FLUSH,
+                             cvox.AbstractTts.PERSONALITY_ANNOUNCEMENT);
+    cvox.ChromeVox.braille.write(
         cvox.NavBraille.fromText(this.msg_('chrome_tab_created')));
-    this.earcons_.playEarcon(cvox.Earcon.OBJECT_OPEN);
+    cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.OBJECT_OPEN);
   },
 
   /**
@@ -73,7 +62,7 @@
     if (!cvox.ChromeVox.isActive) {
       return;
     }
-    this.earcons_.playEarcon(cvox.Earcon.OBJECT_CLOSE);
+    cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.OBJECT_CLOSE);
   },
 
   /**
@@ -90,13 +79,13 @@
         return;
       }
       var title = tab.title ? tab.title : tab.url;
-      this.tts_.speak(this.msg_('chrome_tab_selected',
-                         [title]),
-                     cvox.QueueMode.FLUSH,
-                     cvox.AbstractTts.PERSONALITY_ANNOUNCEMENT);
-      this.braille_.write(
+      cvox.ChromeVox.tts.speak(this.msg_('chrome_tab_selected',
+                                         [title]),
+                               cvox.QueueMode.FLUSH,
+                               cvox.AbstractTts.PERSONALITY_ANNOUNCEMENT);
+      cvox.ChromeVox.braille.write(
           cvox.NavBraille.fromText(this.msg_('chrome_tab_selected', [title])));
-      this.earcons_.playEarcon(cvox.Earcon.OBJECT_SELECT);
+      cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.OBJECT_SELECT);
     }.bind(this));
   },
 
@@ -115,10 +104,10 @@
       }
       if (tab.status == 'loading') {
         this.lastActiveTabLoaded_ = false;
-        this.earcons_.playEarcon(cvox.Earcon.PAGE_START_LOADING);
+        cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.PAGE_START_LOADING);
       } else if (!this.lastActiveTabLoaded_) {
         this.lastActiveTabLoaded_ = true;
-        this.earcons_.playEarcon(cvox.Earcon.PAGE_FINISH_LOADING);
+        cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.PAGE_FINISH_LOADING);
       }
     }.bind(this));
   },
@@ -140,12 +129,12 @@
             'chrome_normal_window_selected';
         var tab = tabs[0] || {};
         var title = tab.title ? tab.title : tab.url;
-        this.tts_.speak(this.msg_(msgId, [title]),
-                       cvox.QueueMode.FLUSH,
-                       cvox.AbstractTts.PERSONALITY_ANNOUNCEMENT);
-        this.braille_.write(
+        cvox.ChromeVox.tts.speak(this.msg_(msgId, [title]),
+                                 cvox.QueueMode.FLUSH,
+                                 cvox.AbstractTts.PERSONALITY_ANNOUNCEMENT);
+        cvox.ChromeVox.braille.write(
             cvox.NavBraille.fromText(this.msg_(msgId, [title])));
-        this.earcons_.playEarcon(cvox.Earcon.OBJECT_SELECT);
+        cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.OBJECT_SELECT);
       }.bind(this));
     }.bind(this));
   }
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/console_tts.js b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/console_tts.js
index 306ab27..caa3559 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/console_tts.js
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/console_tts.js
@@ -41,7 +41,7 @@
       logStr += ' category=' + properties.category;
     }
     logStr += ' "' + textString + '"';
-    window['console']['log'](logStr);
+    console.log(logStr);
   }
   return this;
 };
@@ -52,7 +52,7 @@
 /** @override */
 cvox.ConsoleTts.prototype.stop = function() {
   if (this.enabled_) {
-    window['console']['log']('Stop');
+    console.log('Stop');
   }
 };
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
index 0a32096..0e2eb11 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -13,11 +13,13 @@
 goog.require('AutomationPredicate');
 goog.require('AutomationUtil');
 goog.require('ClassicCompatibility');
+goog.require('NextEarcons');
 goog.require('Output');
 goog.require('Output.EventType');
 goog.require('cursors.Cursor');
 goog.require('cvox.BrailleKeyCommand');
 goog.require('cvox.ChromeVoxEditableTextBase');
+goog.require('cvox.ClassicEarcons');
 goog.require('cvox.ExtensionBridge');
 goog.require('cvox.NavBraille');
 
@@ -115,6 +117,25 @@
         break;
     }
   }.bind(this));
+
+  /** @type {!cvox.AbstractEarcons} @private */
+  this.classicEarcons_ = cvox.ChromeVox.earcons || new cvox.ClassicEarcons();
+
+  /** @type {!cvox.AbstractEarcons} @private */
+  this.nextEarcons_ = new NextEarcons();
+
+  // Turn cvox.ChromeVox.earcons into a getter that returns either the
+  // Next earcons or the Classic earcons depending on the current mode.
+  Object.defineProperty(cvox.ChromeVox, 'earcons', {
+    get: (function() {
+      if (this.mode_ === ChromeVoxMode.FORCE_NEXT ||
+          this.mode_ === ChromeVoxMode.NEXT) {
+        return this.nextEarcons_;
+      } else {
+        return this.classicEarcons_;
+      }
+    }).bind(this)
+  });
 };
 
 Background.prototype = {
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
index a795073..80bb9bf 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -396,3 +396,49 @@
       nonEditable.focus();
     }.bind(this));
 });
+
+TEST_F('BackgroundTest', 'EarconsForControls', function() {
+  var mockFeedback = this.createMockFeedback();
+  this.runWithLoadedTree(
+    function() {/*!
+      <p>Initial focus will be on something that's not a control.</p>
+      <a href="#">MyLink</a>
+      <button>MyButton</button>
+      <input type=checkbox>
+      <input type=checkbox checked>
+      <input>
+      <select multiple><option>1</option></select>
+      <select><option>2</option></select>
+      <input type=range value=5>
+    */},
+    function(rootNode) {
+      var doCmd = this.doCmd.bind(this);
+
+      mockFeedback.call(doCmd('nextElement'))
+          .expectSpeech('MyLink')
+          .expectEarcon(cvox.Earcon.LINK)
+          .call(doCmd('nextElement'))
+          .expectSpeech('MyButton')
+          .expectEarcon(cvox.Earcon.BUTTON)
+          .call(doCmd('nextElement'))
+          .expectSpeech('Check box')
+          .expectEarcon(cvox.Earcon.CHECK_OFF)
+          .call(doCmd('nextElement'))
+          .expectSpeech('Check box')
+          .expectEarcon(cvox.Earcon.CHECK_ON)
+          .call(doCmd('nextElement'))
+          .expectSpeech('Edit text')
+          .expectEarcon(cvox.Earcon.EDITABLE_TEXT)
+          .call(doCmd('nextElement'))
+          .expectSpeech('List box')
+          .expectEarcon(cvox.Earcon.LISTBOX)
+          .call(doCmd('nextElement'))
+          .expectSpeech('Button', 'has pop up')
+          .expectEarcon(cvox.Earcon.POP_UP_BUTTON)
+          .call(doCmd('nextElement'))
+          .expectSpeech(/slider/)
+          .expectEarcon(cvox.Earcon.SLIDER);
+
+      mockFeedback.replay();
+    }.bind(this));
+});
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcon_engine.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcon_engine.js
index fc428c5..83fd6b55 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcon_engine.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/earcon_engine.js
@@ -18,7 +18,7 @@
   // Public control parameters. All of these are meant to be adjustable.
 
   /** @type {number} The master volume, as an amplification factor. */
-  this.masterVolume = 0.2;
+  this.masterVolume = 1.0;
 
   /** @type {number} The base relative pitch adjustment, in half-steps. */
   this.masterPitch = -4;
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/next_earcons.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/next_earcons.js
new file mode 100644
index 0000000..519edc6
--- /dev/null
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/next_earcons.js
@@ -0,0 +1,121 @@
+// 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.
+
+/**
+ * @fileoverview Earcons library that uses EarconEngine to play back
+ * auditory cues.
+ */
+
+
+goog.provide('NextEarcons');
+
+goog.require('EarconEngine');
+goog.require('cvox.AbstractEarcons');
+goog.require('cvox.HostFactory');
+
+
+/**
+ * @constructor
+ * @extends {cvox.AbstractEarcons}
+ */
+NextEarcons = function() {
+  cvox.AbstractEarcons.call(this);
+
+  if (localStorage['earcons'] === 'false') {
+    cvox.AbstractEarcons.enabled = false;
+  }
+
+  /**
+   * @type {EarconEngine}
+   * @private
+   */
+  this.engine_ = new EarconEngine();
+};
+
+NextEarcons.prototype = {
+  /**
+   * @return {string} The human-readable name of the earcon set.
+   */
+  getName: function() {
+    return 'ChromeVox Next earcons';
+  },
+
+  /**
+   * @override
+   */
+  playEarcon: function(earcon) {
+    if (!cvox.AbstractEarcons.enabled) {
+      return;
+    }
+    console.log('Earcon ' + earcon);
+
+    switch (earcon) {
+      case cvox.Earcon.ALERT_MODAL:
+      case cvox.Earcon.ALERT_NONMODAL:
+        this.engine_.onAlert();
+        break;
+      case cvox.Earcon.BUTTON:
+        this.engine_.onButton();
+        break;
+      case cvox.Earcon.CHECK_OFF:
+        this.engine_.onCheckOff();
+        break;
+      case cvox.Earcon.CHECK_ON:
+        this.engine_.onCheckOn();
+        break;
+      case cvox.Earcon.EDITABLE_TEXT:
+        this.engine_.onTextField();
+        break;
+      case cvox.Earcon.INVALID_KEYPRESS:
+        this.engine_.onWrap();
+        break;
+      case cvox.Earcon.LINK:
+        this.engine_.onLink();
+        break;
+      case cvox.Earcon.LISTBOX:
+        this.engine_.onSelect();
+        break;
+      case cvox.Earcon.LIST_ITEM:
+      case cvox.Earcon.LONG_DESC:
+      case cvox.Earcon.MATH:
+      case cvox.Earcon.OBJECT_CLOSE:
+      case cvox.Earcon.OBJECT_ENTER:
+      case cvox.Earcon.OBJECT_EXIT:
+      case cvox.Earcon.OBJECT_OPEN:
+      case cvox.Earcon.OBJECT_SELECT:
+        // TODO(dmazzoni): decide if we want new earcons for these
+        // or not. We may choose to not have earcons for some of these.
+        break;
+      case cvox.Earcon.PAGE_FINISH_LOADING:
+        this.engine_.cancelProgress();
+        break;
+      case cvox.Earcon.PAGE_START_LOADING:
+        // TODO(dmazzoni): only when the page has focus.
+        this.engine_.startProgress();
+        break;
+      case cvox.Earcon.POP_UP_BUTTON:
+        this.engine_.onPopUpButton();
+        break;
+      case cvox.Earcon.RECOVER_FOCUS:
+        // TODO(dmazzoni): decide if we want new earcons for this.
+        break;
+      case cvox.Earcon.SELECTION:
+        this.engine_.onSelection();
+        break;
+      case cvox.Earcon.SELECTION_REVERSE:
+        this.engine_.onSelectionReverse();
+        break;
+      case cvox.Earcon.SKIP:
+        this.engine_.onSkim();
+        break;
+      case cvox.Earcon.SLIDER:
+        this.engine_.onSlider();
+        break;
+      case cvox.Earcon.WRAP:
+      case cvox.Earcon.WRAP_EDGE:
+        this.engine_.onWrap();
+        break;
+    }
+  }
+};
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
index af35f3a..715120b 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -215,13 +215,16 @@
     msgId: 'role_menubar',
   },
   menuItem: {
-    msgId: 'role_menuitem'
+    msgId: 'role_menuitem',
+    earconId: 'BUTTON'
   },
   menuItemCheckBox: {
-    msgId: 'role_menuitemcheckbox'
+    msgId: 'role_menuitemcheckbox',
+    earconId: 'BUTTON'
   },
   menuItemRadio: {
-    msgId: 'role_menuitemradio'
+    msgId: 'role_menuitemradio',
+    earconId: 'BUTTON'
   },
   menuListOption: {
     msgId: 'role_menuitem'
@@ -239,7 +242,6 @@
   },
   popUpButton: {
     msgId: 'role_button',
-    earcon: 'LISTBOX'
   },
   radioButton: {
     msgId: 'role_radio'
@@ -321,15 +323,12 @@
 Output.STATE_INFO_ = {
   checked: {
     on: {
-      earconId: 'CHECK_ON',
       msgId: 'checkbox_checked_state'
     },
     off: {
-      earconId: 'CHECK_OFF',
       msgId: 'checkbox_unchecked_state'
     },
     omitted: {
-      earconId: 'CHECK_OFF',
       msgId: 'checkbox_unchecked_state'
     }
   },
@@ -395,7 +394,8 @@
       enter: '@column_granularity $tableCellColumnIndex'
     },
     checkBox: {
-      speak: '$name $role $checked'
+      speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' +
+             '$name $role $checked'
     },
     dialog: {
       enter: '$name $role'
@@ -446,7 +446,7 @@
       speak: '$descendants'
     },
     popUpButton: {
-      speak: '$value $name $role @aria_has_popup ' +
+      speak: '$earcon(POP_UP_BUTTON) $value $name $role @aria_has_popup ' +
           '$if($collapsed, @aria_expanded_false, @aria_expanded_true)'
     },
     radioButton: {
@@ -463,7 +463,7 @@
       enter: '@row_granularity $tableRowIndex'
     },
     slider: {
-      speak: '@describe_slider($value, $name) $help'
+      speak: '$earcon(SLIDER) @describe_slider($value, $name) $help'
     },
     staticText: {
       speak: '$value='
@@ -690,27 +690,25 @@
     var queueMode = this.speechProperties_['category'] ?
         cvox.QueueMode.CATEGORY_FLUSH : cvox.QueueMode.FLUSH;
     this.speechBuffer_.forEach(function(buff, i, a) {
-      if (buff.toString()) {
-        (function() {
-          var scopedBuff = buff;
-          this.speechProperties_['startCallback'] = function() {
-            var actions = scopedBuff.getSpansInstanceOf(Output.Action);
-            if (actions) {
-              actions.forEach(function(a) {
-                a.run();
-              });
-            }
-          };
-        }.bind(this)());
+      (function() {
+        var scopedBuff = buff;
+        this.speechProperties_['startCallback'] = function() {
+          var actions = scopedBuff.getSpansInstanceOf(Output.Action);
+          if (actions) {
+            actions.forEach(function(a) {
+              a.run();
+            });
+          }
+        };
+      }.bind(this)());
 
-        if (this.speechEndCallback_ && i == a.length - 1)
-          this.speechProperties_['endCallback'] = this.speechEndCallback_;
-        else
-          this.speechProperties_['endCallback'] = null;
-        cvox.ChromeVox.tts.speak(
-            buff.toString(), queueMode, this.speechProperties_);
-        queueMode = cvox.QueueMode.QUEUE;
-      }
+      if (this.speechEndCallback_ && i == a.length - 1)
+        this.speechProperties_['endCallback'] = this.speechEndCallback_;
+      else
+        this.speechProperties_['endCallback'] = null;
+      cvox.ChromeVox.tts.speak(
+          buff.toString(), queueMode, this.speechProperties_);
+      queueMode = cvox.QueueMode.QUEUE;
     }.bind(this));
 
     // Braille.
@@ -967,13 +965,10 @@
             // Ignore unless we're generating speech output.
             if (!this.formatOptions_.speech)
               return;
-            // Assumes there's existing output in our buffer.
-            var lastBuff = buff[buff.length - 1];
-            if (!lastBuff)
-              return;
 
-            lastBuff.setSpan(
-                new Output.EarconAction(tree.firstChild.value), 0, 0);
+            options.annotation.push(
+                new Output.EarconAction(tree.firstChild.value));
+            this.append_(buff, '', options);
           } else if (token == 'countChildren') {
             var role = tree.firstChild.value;
             var count = node.children.filter(function(e) {
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
index ad642ed0..a6940a7 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
@@ -108,14 +108,14 @@
       var el = root.firstChild.firstChild;
       var range = cursors.Range.fromNode(el);
       var o = new Output().withSpeechAndBraille(range, null, 'navigate');
-      assertEqualsJSON({string_: '|Check box|not checked', 'spans_': [
-        // Attributes.
-        {value: 'name', start: 0, end: 0},
-        {value: 'role', start: 1, end: 10},
-        {value: 'state', start: 11, end: 22},
-
+      assertEqualsJSON({string_: '||Check box|not checked', 'spans_': [
         // Checkbox earcon (based on the state).
-        {value: {earconId: 'CHECK_OFF'}, start: 11, end: 22}
+        {value: {earconId: 'CHECK_OFF'}, start: 0, end: 0},
+
+        // Attributes.
+        {value: 'name', start: 1, end: 1},
+        {value: 'role', start: 2, end: 11},
+        {value: 'state', start: 12, end: 23}
       ]}, o.speechOutputForTest);
       checkBrailleOutput(
           'chk ( )',
@@ -223,9 +223,10 @@
       var prevRange = range;
       range = cursors.Range.fromNode(el);
       var o = new Output().withSpeechAndBraille(range, prevRange, 'navigate');
-      assertEqualsJSON({string_: '0, , slider|audio time scrubber',
+      assertEqualsJSON({string_: '|0, , slider|audio time scrubber',
           spans_:
-              [{value: 'help', start: 12, end: 31}]
+              [{value: {'earconId': 'SLIDER'}, start: 0, end: 0},
+               {value: 'help', start: 13, end: 32}]
           }, o.speechOutputForTest);
       // TODO(plundblad): Investigate this.
       checkBrailleOutput(
@@ -453,6 +454,7 @@
     assertEqualsJSON({string_:
             '|Menu|with 1 item|a|Menu item| 1 of 1 ', spans_: [
         {value: 'name', start: 18, end: 19},
+        {value: {earconId: 'BUTTON'}, start:18, end:19},
         {value: 'role', start:20, end: 29}
     ]}, o.speechOutputForTest);
     checkBrailleOutput(
diff --git a/chrome/browser/resources/chromeos/chromevox/host/chrome/earcons_background.js b/chrome/browser/resources/chromeos/chromevox/host/chrome/classic_earcons.js
similarity index 68%
rename from chrome/browser/resources/chromeos/chromevox/host/chrome/earcons_background.js
rename to chrome/browser/resources/chromeos/chromevox/host/chrome/classic_earcons.js
index 500da1a1..d1729c9 100644
--- a/chrome/browser/resources/chromeos/chromevox/host/chrome/earcons_background.js
+++ b/chrome/browser/resources/chromeos/chromevox/host/chrome/classic_earcons.js
@@ -9,7 +9,7 @@
  */
 
 
-goog.provide('cvox.EarconsBackground');
+goog.provide('cvox.ClassicEarcons');
 
 goog.require('cvox.AbstractEarcons');
 
@@ -18,21 +18,22 @@
  * @constructor
  * @extends {cvox.AbstractEarcons}
  */
-cvox.EarconsBackground = function() {
+cvox.ClassicEarcons = function() {
   goog.base(this);
 
-  this.audioMap = new Object();
   if (localStorage['earcons'] === 'false') {
-    this.enabled = false;
+    cvox.AbstractEarcons.enabled = false;
   }
+
+  this.audioMap = new Object();
 };
-goog.inherits(cvox.EarconsBackground, cvox.AbstractEarcons);
+goog.inherits(cvox.ClassicEarcons, cvox.AbstractEarcons);
 
 
 /**
  * @return {string} The human-readable name of the earcon set.
  */
-cvox.EarconsBackground.prototype.getName = function() {
+cvox.ClassicEarcons.prototype.getName = function() {
   return 'ChromeVox earcons';
 };
 
@@ -40,22 +41,20 @@
 /**
  * @return {string} The base URL for loading earcons.
  */
-cvox.EarconsBackground.prototype.getBaseUrl = function() {
-  return cvox.EarconsBackground.BASE_URL;
+cvox.ClassicEarcons.prototype.getBaseUrl = function() {
+  return cvox.ClassicEarcons.BASE_URL;
 };
 
 
 /**
  * @override
  */
-cvox.EarconsBackground.prototype.playEarcon = function(earcon) {
+cvox.ClassicEarcons.prototype.playEarcon = function(earcon) {
   goog.base(this, 'playEarcon', earcon);
-  if (!this.enabled) {
+  if (!cvox.AbstractEarcons.enabled) {
     return;
   }
-  if (window['console']) {
-    window['console']['log']('Earcon ' + earcon);
-  }
+  console.log('Earcon ' + earcon);
 
   this.currentAudio = this.audioMap[earcon];
   if (!this.currentAudio) {
@@ -78,4 +77,4 @@
  * The base URL for  loading eracons.
  * @type {string}
  */
-cvox.EarconsBackground.BASE_URL = 'chromevox/background/earcons/';
+cvox.ClassicEarcons.BASE_URL = 'chromevox/background/earcons/';
diff --git a/chrome/browser/resources/chromeos/chromevox/host/chrome/earcons.js b/chrome/browser/resources/chromeos/chromevox/host/chrome/earcons.js
index c250e8c39..5ac0f81 100644
--- a/chrome/browser/resources/chromeos/chromevox/host/chrome/earcons.js
+++ b/chrome/browser/resources/chromeos/chromevox/host/chrome/earcons.js
@@ -31,7 +31,7 @@
  */
 cvox.ChromeEarcons.prototype.playEarcon = function(earcon) {
   goog.base(this, 'playEarcon', earcon);
-  if (!this.enabled) {
+  if (!cvox.AbstractEarcons.enabled) {
     return;
   }
 
@@ -51,9 +51,9 @@
     'target': 'Prefs',
     'action': 'setPref',
     'pref': 'earcons',
-    'value': this.enabled
+    'value': cvox.AbstractEarcons.enabled
   });
-  if (!this.enabled) {
+  if (!cvox.AbstractEarcons.enabled) {
     cvox.ChromeVox.host.sendToBackgroundPage({
       'target': 'Prefs',
       'action': 'setPref',
@@ -61,8 +61,11 @@
       'value': true
     });
   }
-  return this.enabled;
+  return cvox.AbstractEarcons.enabled;
 };
 
 
+/**
+ * @override
+ */
 cvox.HostFactory.earconsConstructor = cvox.ChromeEarcons;
diff --git a/chrome/browser/resources/chromeos/chromevox/host/chrome/host.js b/chrome/browser/resources/chromeos/chromevox/host/chrome/host.js
index b44711bf..f6db51cd 100644
--- a/chrome/browser/resources/chromeos/chromevox/host/chrome/host.js
+++ b/chrome/browser/resources/chromeos/chromevox/host/chrome/host.js
@@ -62,9 +62,6 @@
 
       cvox.ChromeVox.version = prefs['version'];
 
-      cvox.ChromeVox.earcons.enabled =
-          /** @type {boolean} */(JSON.parse(prefs['earcons']));
-
       cvox.ChromeVox.typingEcho =
           /** @type {number} */(JSON.parse(prefs['typingEcho']));
 
diff --git a/chrome/browser/resources/chromeos/chromevox/host/interface/abstract_earcons.js b/chrome/browser/resources/chromeos/chromevox/host/interface/abstract_earcons.js
index 1dabd1a..c1c5dd1 100644
--- a/chrome/browser/resources/chromeos/chromevox/host/interface/abstract_earcons.js
+++ b/chrome/browser/resources/chromeos/chromevox/host/interface/abstract_earcons.js
@@ -37,10 +37,12 @@
   OBJECT_SELECT: 'object_select',
   PAGE_FINISH_LOADING: 'page_finish_loading',
   PAGE_START_LOADING: 'page_start_loading',
+  POP_UP_BUTTON: 'pop_up_button',
   RECOVER_FOCUS: 'recover_focus',
   SELECTION: 'selection',
   SELECTION_REVERSE: 'selection_reverse',
   SKIP: 'skip',
+  SLIDER: 'slider',
   WRAP: 'wrap',
   WRAP_EDGE: 'wrap_edge',
 };
@@ -50,16 +52,18 @@
  * @constructor
  */
 cvox.AbstractEarcons = function() {
-  /**
-   * Public flag set to enable or disable earcons. Callers should prefer
-   * toggle(); however, this member is public for initialization.
-   * @type {boolean}
-   */
-  this.enabled = true;
 };
 
 
 /**
+ * Public static flag set to enable or disable earcons. Callers should prefer
+ * toggle(); however, this member is public for initialization.
+ * @type {boolean}
+ */
+cvox.AbstractEarcons.enabled = true;
+
+
+/**
  * Plays the specified earcon sound.
  * @param {cvox.Earcon} earcon An earcon identifier.
  */
@@ -81,6 +85,6 @@
  * @return {boolean} True if earcons are now enabled; false otherwise.
  */
 cvox.AbstractEarcons.prototype.toggle = function() {
-  this.enabled = !this.enabled;
-  return this.enabled;
+  cvox.AbstractEarcons.enabled = !cvox.AbstractEarcons.enabled;
+  return cvox.AbstractEarcons.enabled;
 };
diff --git a/chrome/browser/resources/chromeos/chromevox/testing/mock_feedback.js b/chrome/browser/resources/chromeos/chromevox/testing/mock_feedback.js
index e3578aa0..4c846e8 100644
--- a/chrome/browser/resources/chromeos/chromevox/testing/mock_feedback.js
+++ b/chrome/browser/resources/chromeos/chromevox/testing/mock_feedback.js
@@ -3,18 +3,20 @@
 // found in the LICENSE file.
 
 /**
- * @fileoverview This file contains the |MockFeedback| class which is a
- * combined mock class for speech and braille feedback.  A test that uses
- * this class may add expectations for speech utterances and braille display
- * content to be output.  The |install| method sets appropriate mock classes
- * as the |cvox.ChromeVox.tts| and |cvox.ChromeVox.braille| objects,
- * respectively.  Output sent to those objects will then be collected in
- * an internal queue.
+ * @fileoverview This file contains the |MockFeedback| class which is
+ * a combined mock class for speech, braille, and earcon feedback.  A
+ * test that uses this class may add expectations for speech
+ * utterances, braille display content to be output, and earcons
+ * played (by name).  The |install| method sets appropriate mock
+ * classes as the |cvox.ChromeVox.tts|, |cvox.ChromeVox.braille| and
+ * |cvox.ChromeVox.earcons| objects, respectively.  Output sent to
+ * those objects will then be collected in an internal queue.
  *
- * Expectations can be added using the |expectSpeech| and |expectBraille|
- * methods.  These methods take either strings or regular expressions to match
- * against.  Strings must match a full utterance (or display content) exactly,
- * while a regular expression must match a substring (use anchor operators if
+ * Expectations can be added using the |expectSpeech|,
+ * |expectBraille|, and |expectEarcon| methods.  These methods take
+ * either strings or regular expressions to match against.  Strings
+ * must match a full utterance (or display content) exactly, while a
+ * regular expression must match a substring (use anchor operators if
  * needed).
  *
  * Function calls may be inserted in the stream of expectations using the
@@ -22,11 +24,11 @@
  * have been met, and before any further expectations are matched.  Callbacks
  * are called in the order they were added to the mock.
  *
- * The |replay| method starts processing any pending utterances and braille
- * display content and will try to match expectations as new feedback enters
- * the queue asynchronously.  When all expectations have been met and callbacks
- * called, the finish callback, if any was provided to the constructor, is
- * called.
+ * The |replay| method starts processing any pending utterances,
+ * braille display content, and earcons and will try to match
+ * expectations as new feedback enters the queue asynchronously.  When
+ * all expectations have been met and callbacks called, the finish
+ * callback, if any was provided to the constructor, is called.
  *
  * This mock class is lean, meaning that feedback that doesn't match
  * any expectations is silently ignored.
@@ -82,6 +84,12 @@
    */
   this.pendingBraille_ = [];
   /**
+   * Pending earcons.
+   * @type {Array<{text: string, callback: (function|undefined)}>}
+   * @private
+   */
+  this.pendingEarcons_ = [];
+  /**
    * Handle for the timeout set for debug logging.
    * @type {number}
    * @private
@@ -118,6 +126,17 @@
     };
 
     cvox.ChromeVox.braille = new MockBraille();
+
+    var MockEarcons = function() {};
+    MockEarcons.prototype = {
+      __proto__: cvox.AbstractEarcons.prototype,
+      playEarcon: this.addEarcon_.bind(this)
+    };
+
+    // cvox.ChromeVox.earcons is a getter that switches between Classic and
+    // Next; replace it with MockEarcons.
+    delete cvox.ChromeVox.earcons;
+    cvox.ChromeVox.earcons = new MockEarcons();
   },
 
   /**
@@ -197,6 +216,26 @@
   },
 
   /**
+   * Adds an expectation for a played earcon.
+   * @param {string} earconName The name of the earcon.
+   * @return {MockFeedback} |this| for chaining
+   */
+  expectEarcon: function(earconName, opt_props) {
+    assertFalse(this.replaying_);
+    this.pendingActions_.push({
+      perform: function() {
+        var match = MockFeedback.matchAndConsume_(
+            earconName, {}, this.pendingEarcons_);
+        return !!match;
+      }.bind(this),
+      toString: function() {
+        return 'Earcon \'' + earconName + '\'';
+      }
+    });
+    return this;
+  },
+
+  /**
    * Arranges for a callback to be invoked when all expectations that were
    * added before this call have been met.  Callbacks are called in the
    * order they are added.
@@ -270,6 +309,12 @@
     this.process_();
   },
 
+  /** @private */
+  addEarcon_: function(earconName) {
+    this.pendingEarcons_.push({text: earconName});
+    this.process_();
+  },
+
   /*** @private */
   process_: function() {
     if (!this.replaying_ || this.inProcess_)
@@ -324,6 +369,7 @@
     }
     logPending('speech utterances', this.pendingUtterances_);
     logPending('braille', this.pendingBraille_);
+    logPending('earcons', this.pendingEarcons_);
     this.logTimeoutId_ = 0;
   },
 };
@@ -338,7 +384,10 @@
  */
 MockFeedback.matchAndConsume_ = function(text, props, pending) {
   for (var i = 0, candidate; candidate = pending[i]; ++i) {
-    var candidateText = candidate.text.toString();
+    var candidateText = candidate.text;
+    if (typeof(candidateText) != 'string')
+      candidateText = candidateText.toString();
+
     if (text === candidateText ||
         (text instanceof RegExp && text.test(candidateText))) {
       var matched = true;
diff --git a/chrome/browser/resources/chromeos/chromevox/testing/mock_feedback_test.unitjs b/chrome/browser/resources/chromeos/chromevox/testing/mock_feedback_test.unitjs
index 77c8220..5466b773 100644
--- a/chrome/browser/resources/chromeos/chromevox/testing/mock_feedback_test.unitjs
+++ b/chrome/browser/resources/chromeos/chromevox/testing/mock_feedback_test.unitjs
@@ -4,7 +4,7 @@
 
 // Include test fixture.
 GEN_INCLUDE(['chromevox_unittest_base.js',
-            'mock_feedback.js']);
+             'mock_feedback.js']);
 
 function speak(text, opt_properties) {
   cvox.ChromeVox.tts.speak(text, 0, opt_properties);
@@ -16,6 +16,10 @@
   return navBraille;
 }
 
+function earcon(earconName) {
+  cvox.ChromeVox.earcons.playEarcon(cvox.Earcon[earconName]);
+}
+
 /**
  * Test fixture.
  * @constructor
@@ -36,7 +40,8 @@
   closureModuleDeps: [
     'cvox.BrailleInterface',
     'cvox.NavBraille',
-    'cvox.TtsInterface'
+    'cvox.TtsInterface',
+    'cvox.AbstractEarcons'
   ]
 };
 
@@ -170,3 +175,27 @@
       .replay();
   assertTrue(firstCallbackCalled);
 });
+
+TEST_F('MockFeedbackUnitTest', 'SpeechAndEarcons', function() {
+  var finishCalled = false;
+  var mock = new MockFeedback(function() { finishCalled = true; });
+  mock.install();
+  mock.call(function() {
+    speak('MyButton', {startCallback: function() {
+      earcon('BUTTON');
+    }});
+  })
+      .expectSpeech('MyButton')
+      .expectEarcon(cvox.Earcon.BUTTON)
+      .call(function() {
+        earcon('ALERT_MODAL');
+        speak('MyTextField', {startCallback: function() {
+          earcon('EDITABLE_TEXT');
+        }});
+      })
+      .expectEarcon(cvox.Earcon.ALERT_MODAL)
+      .expectSpeech('MyTextField')
+      .expectEarcon(cvox.Earcon.EDITABLE_TEXT)
+      .replay();
+  assertTrue(finishCalled);
+});
diff --git a/chrome/browser/resources/extensions/compiled_resources.gyp b/chrome/browser/resources/extensions/compiled_resources.gyp
index a40ae06..7779b4e 100644
--- a/chrome/browser/resources/extensions/compiled_resources.gyp
+++ b/chrome/browser/resources/extensions/compiled_resources.gyp
@@ -32,9 +32,9 @@
           'focus_row.js',
         ],
         'externs': [
-          '<(EXTERNS_DIR)/chrome_extensions.js',
           '<(EXTERNS_DIR)/chrome_send.js',
           '<(EXTERNS_DIR)/developer_private.js',
+          '<(EXTERNS_DIR)/management.js',
         ],
       },
       'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'],
diff --git a/chrome/browser/resources/extensions/extension_command_list.js b/chrome/browser/resources/extensions/extension_command_list.js
index 9974fb7..49e05301 100644
--- a/chrome/browser/resources/extensions/extension_command_list.js
+++ b/chrome/browser/resources/extensions/extension_command_list.js
@@ -2,16 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/** @typedef {{active: boolean,
- *             command_name: string,
- *             description: string,
- *             extension_action: boolean,
- *             extension_id: string,
- *             global: boolean,
- *             keybinding: string}}
- */
-var ExtensionCommand;
-
 cr.define('options', function() {
   'use strict';
 
@@ -217,10 +207,11 @@
 
     /**
      * Updates the extensions data for the overlay.
-     * @param {!Array<ExtensionInfo>} data The extension data.
+     * @param {!Array<chrome.developerPrivate.ExtensionInfo>} data The extension
+     *     data.
      */
     setData: function(data) {
-      /** @private {!Array<ExtensionInfo>} */
+      /** @private {!Array<chrome.developerPrivate.ExtensionInfo>} */
       this.data_ = data;
 
       this.textContent = '';
@@ -232,7 +223,8 @@
     /**
      * Synthesizes and initializes an HTML element for the extension command
      * metadata given in |extension|.
-     * @param {ExtensionInfo} extension A dictionary of extension metadata.
+     * @param {chrome.developerPrivate.ExtensionInfo} extension A dictionary of
+     *     extension metadata.
      * @private
      */
     createNodeForExtension_: function(extension) {
@@ -259,7 +251,8 @@
      * Synthesizes and initializes an HTML element for the extension command
      * metadata given in |command|.
      * @param {string} extensionId The associated extension's id.
-     * @param {Command} command A dictionary of extension command metadata.
+     * @param {chrome.developerPrivate.Command} command A dictionary of
+     *     extension command metadata.
      * @private
      */
     createNodeForCommand_: function(extensionId, command) {
diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.js b/chrome/browser/resources/extensions/extension_commands_overlay.js
index 9b51f34..6e0e43a 100644
--- a/chrome/browser/resources/extensions/extension_commands_overlay.js
+++ b/chrome/browser/resources/extensions/extension_commands_overlay.js
@@ -54,7 +54,7 @@
   /**
    * Called by the dom_ui_ to re-populate the page with data representing
    * the current state of extension commands.
-   * @param {!Array<ExtensionInfo>} extensionsData
+   * @param {!Array<chrome.developerPrivate.ExtensionInfo>} extensionsData
    */
   ExtensionCommandsOverlay.updateExtensionsData = function(extensionsData) {
     var overlay = ExtensionCommandsOverlay.getInstance();
diff --git a/chrome/browser/resources/extensions/extension_error.js b/chrome/browser/resources/extensions/extension_error.js
index 9ad71e8..0f50425 100644
--- a/chrome/browser/resources/extensions/extension_error.js
+++ b/chrome/browser/resources/extensions/extension_error.js
@@ -195,7 +195,7 @@
 
       /**
        * The callback for the extension changed event.
-       * @private {function(EventData):void}
+       * @private {function(chrome.developerPrivate.EventData):void}
        */
       this.onItemStateChangedListener_ = function(data) {
         var type = chrome.developerPrivate.EventType;
diff --git a/chrome/browser/resources/extensions/extension_error_overlay.js b/chrome/browser/resources/extensions/extension_error_overlay.js
index 1f7975e..3acfef97 100644
--- a/chrome/browser/resources/extensions/extension_error_overlay.js
+++ b/chrome/browser/resources/extensions/extension_error_overlay.js
@@ -2,6 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+
+/** @typedef {chrome.developerPrivate.RuntimeError} */
+var RuntimeError;
+/** @typedef {chrome.developerPrivate.ManifestError} */
+var ManifestError;
+
 cr.define('extensions', function() {
   'use strict';
 
@@ -465,7 +471,8 @@
 
     /**
      * Requests a file's source.
-     * @param {RequestFileSourceProperties} args The arguments for the call.
+     * @param {chrome.developerPrivate.RequestFileSourceProperties} args The
+     *     arguments for the call.
      */
     requestFileSource: function(args) {
       chrome.developerPrivate.requestFileSource(
@@ -475,10 +482,10 @@
     /**
      * Set the code to be displayed in the code portion of the overlay.
      * @see ExtensionErrorOverlay.requestFileSourceResponse().
-     * @param {?RequestFileSourceResponse} response The response from the
-     *     request file source call, which will be shown as code. If |response|
-     *     is null, then a "Could not display code" message will be displayed
-     *     instead.
+     * @param {?chrome.developerPrivate.RequestFileSourceResponse} response The
+     *     response from the request file source call, which will be shown as
+     *     code. If |response| is null, then a "Could not display code" message
+     *     will be displayed instead.
      */
     onFileSourceResponse_: function(response) {
       this.codeDiv_.populate(
diff --git a/chrome/browser/resources/extensions/extension_list.js b/chrome/browser/resources/extensions/extension_list.js
index 2bbed63..c59e385 100644
--- a/chrome/browser/resources/extensions/extension_list.js
+++ b/chrome/browser/resources/extensions/extension_list.js
@@ -66,8 +66,8 @@
 
   /**
    * Compares two extensions for the order they should appear in the list.
-   * @param {ExtensionInfo} a The first extension.
-   * @param {ExtensionInfo} b The second extension.
+   * @param {chrome.developerPrivate.ExtensionInfo} a The first extension.
+   * @param {chrome.developerPrivate.ExtensionInfo} b The second extension.
    * returns {number} -1 if A comes before B, 1 if A comes after B, 0 if equal.
    */
   function compareExtensions(a, b) {
@@ -163,7 +163,7 @@
      * @param {!extensions.ExtensionListDelegate} delegate
      */
     initialize: function(delegate) {
-      /** @private {!Array<ExtensionInfo>} */
+      /** @private {!Array<chrome.developerPrivate.ExtensionInfo>} */
       this.extensions_ = [];
 
       /** @private {!extensions.ExtensionListDelegate} */
@@ -408,7 +408,8 @@
     /**
      * Synthesizes and initializes an HTML element for the extension metadata
      * given in |extension|.
-     * @param {!ExtensionInfo} extension A dictionary of extension metadata.
+     * @param {!chrome.developerPrivate.ExtensionInfo} extension A dictionary
+     *     of extension metadata.
      * @param {?Element} nextWrapper The newly created wrapper will be inserted
      *     before |nextWrapper| if non-null (else it will be appended to the
      *     wrapper list).
@@ -602,7 +603,8 @@
 
     /**
      * Updates an HTML element for the extension metadata given in |extension|.
-     * @param {!ExtensionInfo} extension A dictionary of extension metadata.
+     * @param {!chrome.developerPrivate.ExtensionInfo} extension A dictionary of
+     *     extension metadata.
      * @param {!Element} wrapper The extension wrapper element to update.
      * @private
      */
@@ -1047,8 +1049,8 @@
 
     /**
      * Updates or creates a wrapper for |extension|.
-     * @param {!ExtensionInfo} extension The information about the extension to
-     *     update.
+     * @param {!chrome.developerPrivate.ExtensionInfo} extension The information
+     *     about the extension to update.
      * @private
      */
     updateOrCreateWrapper_: function(extension) {
diff --git a/chrome/browser/resources/extensions/extensions.js b/chrome/browser/resources/extensions/extensions.js
index e957033..ceeea64 100644
--- a/chrome/browser/resources/extensions/extensions.js
+++ b/chrome/browser/resources/extensions/extensions.js
@@ -243,7 +243,7 @@
     /**
      * [Re]-Populates the page with data representing the current state of
      * installed extensions.
-     * @param {ProfileInfo} profileInfo
+     * @param {chrome.developerPrivate.ProfileInfo} profileInfo
      * @private
      */
     update_: function(profileInfo) {
diff --git a/chrome/browser/resources/extensions/pack_extension_overlay.js b/chrome/browser/resources/extensions/pack_extension_overlay.js
index 05d23d1..63b20a4d 100644
--- a/chrome/browser/resources/extensions/pack_extension_overlay.js
+++ b/chrome/browser/resources/extensions/pack_extension_overlay.js
@@ -97,7 +97,8 @@
 
     /**
      * Handles a response from a packDirectory call.
-     * @param {PackDirectoryResponse} response The response of the pack call.
+     * @param {chrome.developerPrivate.PackDirectoryResponse} response The
+     *     response of the pack call.
      * @private
      */
     onPackResponse_: function(response) {
diff --git a/chrome/browser/resources/settings/controls/compiled_resources.gyp b/chrome/browser/resources/settings/controls/compiled_resources.gyp
index ae603dbc..17cd860d 100644
--- a/chrome/browser/resources/settings/controls/compiled_resources.gyp
+++ b/chrome/browser/resources/settings/controls/compiled_resources.gyp
@@ -7,7 +7,10 @@
       'target_name': 'settings_checkbox',
       'variables': {
         'depends': [
-          '../policy_controllable/policy_controllable.js',
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
+          '../../../../../ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator_behavior.js',
+          '../../../../../ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_behavior.js',
         ],
         'externs': [
           '../../../../../third_party/closure_compiler/externs/settings_private.js'
@@ -20,7 +23,9 @@
       'variables': {
         'depends': [
           '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
-          '../policy_controllable/policy_controllable.js',
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
+          '../../../../../ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator_behavior.js',
+          '../../../../../ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_behavior.js',
         ],
         'externs': [
           '../../../../../third_party/closure_compiler/externs/settings_private.js'
diff --git a/chrome/browser/resources/settings/controls/settings_checkbox.html b/chrome/browser/resources/settings/controls/settings_checkbox.html
index 25a3cae..4a279814 100644
--- a/chrome/browser/resources/settings/controls/settings_checkbox.html
+++ b/chrome/browser/resources/settings/controls/settings_checkbox.html
@@ -1,8 +1,8 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html">
 <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_events/cr_events.html">
-<link rel="import" href="chrome://resources/cr_elements/v1_0/policy/cr_policy_indicator.html">
-<link rel="import" href="chrome://md-settings/policy_controllable/policy_controllable.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/policy/cr_policy_pref_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/policy/cr_policy_pref_indicator.html">
 <link rel="import" href="chrome://md-settings/pref_tracker/pref_tracker.html">
 
 <dom-module id="settings-checkbox">
@@ -17,7 +17,7 @@
         <span id="mainLabel">{{label}}</span>
         <span id="subLabel">{{subLabel}}</span>
       </paper-checkbox>
-      <cr-policy-indicator pref="[[pref]]"></cr-policy-indicator>
+      <cr-policy-pref-indicator pref="[[pref]]"></cr-policy-pref-indicator>
     </div>
   </template>
   <script src="settings_checkbox.js"></script>
diff --git a/chrome/browser/resources/settings/controls/settings_checkbox.js b/chrome/browser/resources/settings/controls/settings_checkbox.js
index 5a6134b..e892fb9 100644
--- a/chrome/browser/resources/settings/controls/settings_checkbox.js
+++ b/chrome/browser/resources/settings/controls/settings_checkbox.js
@@ -16,12 +16,12 @@
 Polymer({
   is: 'settings-checkbox',
 
-  behaviors: [PolicyControllable],
+  behaviors: [CrPolicyPrefBehavior],
 
   properties: {
     /**
      * The boolean preference object to control.
-     * @type {?chrome.settingsPrivate.PrefObject}
+     * @type {!chrome.settingsPrivate.PrefObject|undefined}
      */
     pref: {
       type: Object,
@@ -101,11 +101,11 @@
 
   /**
    * @param {boolean} disabled
-   * @param {?chrome.settingsPrivate.PrefObject} pref
+   * @param {!chrome.settingsPrivate.PrefObject} pref
    * @return {boolean} Whether the checkbox should be disabled.
    * @private
    */
   checkboxDisabled_: function(disabled, pref) {
-    return disabled || this.isPolicyControlled(pref);
+    return disabled || this.isPrefPolicyControlled(pref);
   },
 });
diff --git a/chrome/browser/resources/settings/controls/settings_input.html b/chrome/browser/resources/settings/controls/settings_input.html
index 3db53397..26f40f5 100644
--- a/chrome/browser/resources/settings/controls/settings_input.html
+++ b/chrome/browser/resources/settings/controls/settings_input.html
@@ -1,7 +1,8 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
 <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_events/cr_events.html">
-<link rel="import" href="chrome://md-settings/policy_controllable/policy_controllable.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/policy/cr_policy_pref_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/policy/cr_policy_pref_indicator.html">
 <link rel="import" href="chrome://md-settings/pref_tracker/pref_tracker.html">
 
 <dom-module id="settings-input">
@@ -17,7 +18,7 @@
           readonly$="[[readonly]]" required="[[required]]" type="[[type]]"
           on-blur="onBlur_" disabled="[[isDisabled_(disabled, pref)]]">
       </paper-input>
-      <cr-policy-indicator pref="[[pref]]"></cr-policy-indicator>
+      <cr-policy-pref-indicator pref="[[pref]]"></cr-policy-pref-indicator>
     </div>
   </template>
   <script src="settings_input.js"></script>
diff --git a/chrome/browser/resources/settings/controls/settings_input.js b/chrome/browser/resources/settings/controls/settings_input.js
index 5c1d957..ab0cfe5 100644
--- a/chrome/browser/resources/settings/controls/settings_input.js
+++ b/chrome/browser/resources/settings/controls/settings_input.js
@@ -12,12 +12,12 @@
 Polymer({
   is: 'settings-input',
 
-  behaviors: [PolicyControllable],
+  behaviors: [CrPolicyPrefBehavior],
 
   properties: {
     /**
      * The preference object to control.
-     * @type {chrome.settingsPrivate.PrefObject|undefined}
+     * @type {!chrome.settingsPrivate.PrefObject|undefined}
      */
     pref: {
       type: Object,
@@ -128,11 +128,11 @@
 
   /**
    * @param {boolean} disabled
-   * @param {?chrome.settingsPrivate.PrefObject} pref
+   * @param {!chrome.settingsPrivate.PrefObject} pref
    * @return {boolean} Whether the element should be disabled.
    * @private
    */
   isDisabled_: function(disabled, pref) {
-    return disabled || this.isPolicyControlled(pref);
+    return disabled || this.isPrefPolicyControlled(pref);
   },
 });
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.css b/chrome/browser/resources/settings/internet_page/internet_detail_page.css
index 684a613e..633a05e 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.css
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.css
@@ -2,65 +2,48 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
-#titleDiv {
-  margin-bottom: 10px;
+.section {
+  margin-bottom: 5px;
 }
 
-#outerDiv {
-  margin: 0 40px;
+cr-collapse {
+  margin: 10px;
 }
 
-#networkIcon {
+cr-network-icon {
   height: 32px;
   width: 32px;
 }
 
-#networkName {
-  -webkit-margin-start: 10px;
-  font-size: 20px;
-  font-weight: bold;
-}
-
+#networkName,
 #networkState {
   -webkit-margin-start: 10px;
   font-size: 20px;
 }
 
+#networkName {
+  font-weight: bold;
+}
+
 #networkState[connected] {
   color: green;
 }
 
-#simInfoDiv {
-  margin-left: 10px;
+#outerDiv {
+  margin: 10px 20px;
 }
 
-#infoDiv {
-  margin-left: 10px;
-}
-
-#infoDiv span {
-  margin-bottom: 8px;
+#ipAddressLabel {
+  -webkit-margin-end: 10px;
+  font-weight: bold;
 }
 
 #preferButton {
-  margin: 0 7px 8px -2px;
+  -webkit-margin-end: 8px;
+  -webkit-margin-start: -3px;
   padding: 0
 }
 
-#advancedDiv paper-button {
-  --paper-button: {
-    text-align: start;
-  };
-}
-
 #proxyDiv {
   max-width: 500px;
 }
-
-paper-checkbox {
-  margin-bottom: 10px;
-}
-
-cr-collapse {
-  margin: 10px;
-}
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
index 9304312e..827de6a 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -22,7 +22,7 @@
     <div class="layout vertical">
       <!-- Title section: Icon + name + connection state. -->
       <div id="titleDiv" class="layout horizontal center">
-        <cr-network-icon id="networkIcon" network-state="[[networkProperties]]">
+        <cr-network-icon network-state="[[networkProperties]]">
         </cr-network-icon>
         <span id="networkName">[[getStateName_(networkProperties)]]</span>
         <span id="networkState"
@@ -32,7 +32,7 @@
 
       <div id="outerDiv" class="layout vertical">
         <!-- For Cellular, show SIM info first. -->
-        <div id="simInfoDiv" class="layout vertical">
+        <div class="layout vertical section">
           <network-siminfo editable
               hidden$="[[!showCellularSim_(networkProperties)]]"
               network-properties="[[networkProperties]]"
@@ -42,14 +42,16 @@
 
         <!-- Info and properties common to all networks. -->
         <div id="infoDiv" class="layout vertical">
-          <div class="layout horizontal" hidden$="[[!IPAddress]]">
-            <span>IP Address:</span>
+          <div class="layout horizontal section" hidden$="[[!IPAddress]]">
+            <span id="ipAddressLabel">IP Address:</span>
             <span>[[IPAddress]]</span>
           </div>
-          <span hidden$="[[!showShared_(networkProperties)]]">
-            This network is shared with other users.
-          </span>
-          <div class="layout horizontal center"
+          <div class="section">
+            <span hidden$="[[!showShared_(networkProperties)]]">
+              This network is shared with other users.
+            </span>
+          </div>
+          <div class="layout horizontal center section"
               hidden$="[[!showPreferNetwork_(networkProperties)]]">
             <paper-icon-button id="preferButton"
                 toggles active="{{preferNetwork}}"
@@ -57,20 +59,23 @@
             </paper-icon-button>
             <span>Prefer this network</span>
           </div>
-          <paper-checkbox checked="{{autoConnect}}"
-              hidden$="[[!showAutoConnect_(networkProperties)]]">
-            Automatically connect to this network
-          </paper-checkbox>
-
+          <div class="section">
+            <paper-checkbox checked="{{autoConnect}}"
+                hidden$="[[!showAutoConnect_(networkProperties)]]">
+              Automatically connect to this network
+            </paper-checkbox>
+          </div>
           <!-- Properties to always show if present. -->
-          <network-property-list
-              fields="[[getInfoFields_(networkProperties)]]"
-              property-dict="[[networkProperties]]">
-          </network-property-list>
+          <div class="section">
+            <network-property-list
+                fields="[[getInfoFields_(networkProperties)]]"
+                property-dict="[[networkProperties]]">
+            </network-property-list>
+          </div>
         </div>
 
         <!-- Button row: Advanced + Disconnect | Connect. -->
-        <div class="layout horizontal center">
+        <div id="buttonDiv" class="layout horizontal center">
           <paper-button toggles noink active="{{advancedExpanded}}"
               hidden$="[[!hasAdvancedOrDeviceFields_(networkProperties)]]">
             Advanced
@@ -100,7 +105,7 @@
             hidden$="[[!hasAdvancedOrDeviceFields_(networkProperties)]]">
           <cr-collapse opened="[[advancedExpanded]]">
             <!-- Advanced properties -->
-            <div id="advancedInfoDiv" class="layout vertical">
+            <div id="advancedInfoDiv" class="layout vertical section">
               <network-property-list
                   fields="[[getAdvancedFields_(networkProperties)]]"
                   property-dict="[[networkProperties]]">
@@ -108,13 +113,15 @@
             </div>
 
             <!-- Network (APN, address, nameservers) -->
-            <div id="addressDiv" class="layout vertical"
+            <div id="addressDiv" class="layout vertical section"
                 hidden$="[[!hasNetworkSection_(networkProperties)]]">
-              <paper-button toggles noink active="{{addressExpanded}}">
-                Network
-              </paper-button>
+              <div>
+                <paper-button toggles noink active="{{addressExpanded}}">
+                  Network
+                </paper-button>
+              </div>
               <cr-collapse opened="[[addressExpanded]]">
-                <div class="layout vertical flex">
+                <div class="layout vertical">
                   <network-apnlist editable
                       hidden$="[[!isType_(networkProperties, NetworkType.CELLULAR)]]"
                       network-properties="[[networkProperties]]"
@@ -133,13 +140,15 @@
             </div>
 
             <!-- Proxy -->
-            <div class="layout vertical"
+            <div class="layout vertical section"
                 hidden$="[[!hasNetworkSection_(networkProperties)]]">
-              <paper-button toggles noink active="{{proxyExpanded}}">
-                Proxy
-              </paper-button>
+              <div>
+                <paper-button toggles noink active="{{proxyExpanded}}">
+                  Proxy
+                </paper-button>
+              </div>
               <cr-collapse opened="[[proxyExpanded]]">
-                <div id="proxyDiv" class="layout vertical flex">
+                <div id="proxyDiv" class="layout vertical">
                   <network-proxy editable
                       network-properties="[[networkProperties]]"
                       on-proxy-change="onProxyChange_">
@@ -149,17 +158,18 @@
             </div>
 
             <!-- Device properties -->
-            <div class="layout vertical"
+            <div class="layout vertical section"
                 hidden$="[[!hasDeviceFields_(networkProperties)]]">
-              <paper-button toggles noink active="{{deviceExpanded}}">
-                Device
-              </paper-button>
+              <div>
+                <paper-button toggles noink active="{{deviceExpanded}}">
+                  Device
+                </paper-button>
+              </div>
               <cr-collapse opened="[[deviceExpanded]]">
                 <network-property-list
                     fields="[[getDeviceFields_(networkProperties)]]"
                     property-dict="[[networkProperties]]">
                 </network-property-list>
-                <!-- TODO(stevenjb): Cellular SIM -->
               </cr-collapse>
             </div>
           </cr-collapse>
diff --git a/chrome/browser/resources/settings/internet_page/network_apnlist.css b/chrome/browser/resources/settings/internet_page/network_apnlist.css
index 233cc8c..3f7caed 100644
--- a/chrome/browser/resources/settings/internet_page/network_apnlist.css
+++ b/chrome/browser/resources/settings/internet_page/network_apnlist.css
@@ -6,9 +6,12 @@
   margin-bottom: 10px;
 }
 
+#selectDiv {
+  margin-bottom: 10px;
+}
+
 #selectDiv select {
-  font-size: 16px;
-  margin: 10px 0 10px 5px;
+  margin-left: 10px;
   padding: 5px;
 }
 
diff --git a/chrome/browser/resources/settings/internet_page/network_nameservers.css b/chrome/browser/resources/settings/internet_page/network_nameservers.css
index 3dda85c..d94c3c9 100644
--- a/chrome/browser/resources/settings/internet_page/network_nameservers.css
+++ b/chrome/browser/resources/settings/internet_page/network_nameservers.css
@@ -2,10 +2,11 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+#selectTypeDiv {
+  margin: 10px 0;
+}
+
 select {
-  font-size: 16px;
-  margin-bottom: 10px;
-  margin-top: 10px;
   padding: 5px;
 }
 
diff --git a/chrome/browser/resources/settings/internet_page/network_nameservers.html b/chrome/browser/resources/settings/internet_page/network_nameservers.html
index 3b1b6f1b..f09c1326 100644
--- a/chrome/browser/resources/settings/internet_page/network_nameservers.html
+++ b/chrome/browser/resources/settings/internet_page/network_nameservers.html
@@ -6,7 +6,7 @@
   <link rel="import" type="css" href="network_nameservers.css">
   <template>
     <div id="outer" class="layout vertical">
-      <div>
+      <div id="selectTypeDiv">
         <!-- TODO(stevenjb): Use cr-dropdown-menu once available. -->
         <select id="type" on-change="onTypeChange_">
           <template is="dom-repeat" items="[[nameserverTypeNames_]]">
diff --git a/chrome/browser/resources/settings/internet_page/network_property_list.css b/chrome/browser/resources/settings/internet_page/network_property_list.css
index edad310..f63baf8 100644
--- a/chrome/browser/resources/settings/internet_page/network_property_list.css
+++ b/chrome/browser/resources/settings/internet_page/network_property_list.css
@@ -3,7 +3,8 @@
  * found in the LICENSE file. */
 
 span {
-  margin: 0 5px 5px 0;
+  -webkit-margin-end: 5px;
+  margin-bottom: 5px;
 }
 
 span.fill {
@@ -14,5 +15,11 @@
 }
 
 paper-input-container {
-  margin: -8px 0 -3px 5px;
+  -webkit-margin-start: 5px;
+  margin-bottom: -3px;
+  margin-top: -12px;
+}
+
+#outerDiv {
+  padding: 5px 0;
 }
diff --git a/chrome/browser/resources/settings/internet_page/network_property_list.html b/chrome/browser/resources/settings/internet_page/network_property_list.html
index bc89ad75..dce7aed 100644
--- a/chrome/browser/resources/settings/internet_page/network_property_list.html
+++ b/chrome/browser/resources/settings/internet_page/network_property_list.html
@@ -5,7 +5,7 @@
 <dom-module name="network-property-list">
   <link rel="import" type="css" href="network_property_list.css">
   <template>
-    <div class="layout horizontal">
+    <div id="outerDiv" class="layout horizontal">
       <div class="layout vertical">
         <template is="dom-repeat" items="[[fields]]">
           <div class="layout horizontal"
diff --git a/chrome/browser/resources/settings/internet_page/network_proxy.css b/chrome/browser/resources/settings/internet_page/network_proxy.css
index 0b3794a..bf734a04 100644
--- a/chrome/browser/resources/settings/internet_page/network_proxy.css
+++ b/chrome/browser/resources/settings/internet_page/network_proxy.css
@@ -6,10 +6,11 @@
   display: inline-block;
 }
 
+#selectDiv {
+  margin: 10px 0;
+}
+
 select {
-  font-size: 16px;
-  margin-bottom: 10px;
-  margin-top: 10px;
   padding: 5px;
 }
 
diff --git a/chrome/browser/resources/settings/internet_page/network_proxy.html b/chrome/browser/resources/settings/internet_page/network_proxy.html
index 826a535..f6a3737 100644
--- a/chrome/browser/resources/settings/internet_page/network_proxy.html
+++ b/chrome/browser/resources/settings/internet_page/network_proxy.html
@@ -12,7 +12,7 @@
   <template>
     <div id="outer" class="layout vertical flex">
       <!-- TODO(stevenjb): Use cr-dropdown-menu once available. -->
-      <div>
+      <div id="selectDiv">
         <select id="selectType" on-change="onTypeChange_">
           <template is="dom-repeat" items="[[proxyTypes_]]">
             <option value="[[item]]">[[proxyTypeDesc_(item)]]</option>
diff --git a/chrome/browser/resources/settings/internet_page/network_siminfo.css b/chrome/browser/resources/settings/internet_page/network_siminfo.css
index 2f31161..df0d574 100644
--- a/chrome/browser/resources/settings/internet_page/network_siminfo.css
+++ b/chrome/browser/resources/settings/internet_page/network_siminfo.css
@@ -2,16 +2,17 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+iron-icon {
+ -webkit-margin-end: 5px;
+ -webkit-margin-start: -3px;
+}
+
+paper-button {
+  margin: 0;
+}
+
 span {
-  margin-right: 10px;
-}
-
-#outerDiv {
-  margin-bottom: 10px;
-}
-
-#lockedDiv iron-icon {
-  margin: 0 5px 0 -2px;
+  -webkit-margin-end: 10px;
 }
 
 #lockedDiv span {
@@ -20,16 +21,16 @@
 }
 
 #lockedDiv paper-input {
-  margin-left: 10px;
+  -webkit-margin-start: 10px;
   width: 80px;
 }
 
 #unlockSimDialog paper-input {
-  margin-left: 5px;
+  -webkit-margin-start: 5px;
 }
 
 #unlockSimDialog span {
-  margin-left: 5px;
+  -webkit-margin-start: 5px;
 }
 
 .pin {
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.css b/chrome/browser/resources/settings/internet_page/network_summary.css
deleted file mode 100644
index 8ef2212..0000000
--- a/chrome/browser/resources/settings/internet_page/network_summary.css
+++ /dev/null
@@ -1,7 +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. */
-
-#summary {
-  padding-right: 40px;
-}
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.html b/chrome/browser/resources/settings/internet_page/network_summary.html
index 9e3f8d7..c92c9e7 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary.html
@@ -3,7 +3,6 @@
 <link rel="import" href="network_summary_item.html">
 
 <dom-module id="network-summary">
-  <link rel="import" type="css" href="network_summary.css">
   <template>
     <div id="summary" class="layout vertical">
       <network-summary-item id="ethernet"
diff --git a/chrome/browser/resources/settings/languages_page/compiled_resources.gyp b/chrome/browser/resources/settings/languages_page/compiled_resources.gyp
index ea0bdf4..d62d2df 100644
--- a/chrome/browser/resources/settings/languages_page/compiled_resources.gyp
+++ b/chrome/browser/resources/settings/languages_page/compiled_resources.gyp
@@ -23,7 +23,7 @@
       'target_name': 'language_detail_page',
       'variables': {
         'depends': [
-          '../../../../../ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator.js',
+          '../../../../../ui/webui/resources/cr_elements/v1_0/policy/compiled_resources.gyp:cr_policy_indicator_behavior',
           '../../../../../ui/webui/resources/js/chromeos/compiled_resources.gyp:ui_account_tweaks',
           '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
           '../prefs/compiled_resources.gyp:prefs',
diff --git a/chrome/browser/resources/settings/languages_page/language_detail_page.html b/chrome/browser/resources/settings/languages_page/language_detail_page.html
index e3ea064..39ff9c9 100644
--- a/chrome/browser/resources/settings/languages_page/language_detail_page.html
+++ b/chrome/browser/resources/settings/languages_page/language_detail_page.html
@@ -1,7 +1,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
-<link rel="import" href="chrome://resources/cr_elements/v1_0/policy/cr_policy_indicator.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/policy/cr_policy_pref_indicator.html">
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="languages.html">
@@ -33,7 +33,8 @@
               hidden$="[[!isRestartRequired_(detail.language.code, prefs.intl.app_locale.value)]]">
           </paper-button>
         </span>
-        <cr-policy-indicator id="policyIndicator"></cr-policy-indicator>
+        <cr-policy-pref-indicator id="policyIndicator">
+        </cr-policy-pref-indicator>
       </label>
       <span i18n-content="cannotBeDisplayedInThisLanguage"
           hidden$="[[detail.language.supportsUI]]"></span>
diff --git a/chrome/browser/resources/settings/languages_page/language_detail_page.js b/chrome/browser/resources/settings/languages_page/language_detail_page.js
index b30d2a9..b3b9166 100644
--- a/chrome/browser/resources/settings/languages_page/language_detail_page.js
+++ b/chrome/browser/resources/settings/languages_page/language_detail_page.js
@@ -39,7 +39,7 @@
     // In a CrOS multi-user session, the primary user controls the UI language.
     if (this.isSecondaryUser_()) {
       var indicator = this.$.policyIndicator;
-      indicator.indicatorType = CrPolicyIndicator.Type.PRIMARY_USER;
+      indicator.indicatorType = CrPolicyIndicatorType.PRIMARY_USER;
       indicator.controllingUser = loadTimeData.getString('primaryUserEmail');
     }
 
diff --git a/chrome/browser/resources/settings/policy_controllable/policy_controllable.html b/chrome/browser/resources/settings/policy_controllable/policy_controllable.html
deleted file mode 100644
index c5a1da9..0000000
--- a/chrome/browser/resources/settings/policy_controllable/policy_controllable.html
+++ /dev/null
@@ -1 +0,0 @@
-<script src="policy_controllable.js"></script>
diff --git a/chrome/browser/resources/settings/policy_controllable/policy_controllable.js b/chrome/browser/resources/settings/policy_controllable/policy_controllable.js
deleted file mode 100644
index 3298d3d0..0000000
--- a/chrome/browser/resources/settings/policy_controllable/policy_controllable.js
+++ /dev/null
@@ -1,20 +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.
-
-/**
- * @fileoverview Behavior to determine whether a pref is controlled by policy.
- */
-
-/** @polymerBehavior */
-var PolicyControllable = {
-  /**
-   * @param {?chrome.settingsPrivate.PrefObject} pref
-   * @return {boolean} True if the pref is controlled by an enforced policy.
-   */
-  isPolicyControlled: function(pref) {
-    return !!pref &&
-            pref.policyEnforcement ==
-                chrome.settingsPrivate.PolicyEnforcement.ENFORCED;
-  },
-};
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index 70785765..b75cc76a 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -253,12 +253,6 @@
       <structure name="IDR_SETTINGS_LANGUAGES_LANGUAGE_DETAIL_PAGE_JS"
                  file="languages_page/language_detail_page.js"
                  type="chrome_html" />
-      <structure name="IDR_SETTINGS_POLICY_CONTROLLABLE_HTML"
-                 file="policy_controllable/policy_controllable.html"
-                 type="chrome_html" />
-      <structure name="IDR_SETTINGS_POLICY_CONTROLLABLE_JS"
-                 file="policy_controllable/policy_controllable.js"
-                 type="chrome_html" />
       <structure name="IDR_SETTINGS_PREFS_HTML"
                  file="prefs/prefs.html"
                  type="chrome_html" />
@@ -505,9 +499,6 @@
         <structure name="IDR_SETTINGS_NETWORK_SIMINFO_JS"
                    file="internet_page/network_siminfo.js"
                    type="chrome_html" />
-        <structure name="IDR_SETTINGS_NETWORK_SUMMARY_CSS"
-                   file="internet_page/network_summary.css"
-                   type="chrome_html" />
         <structure name="IDR_SETTINGS_NETWORK_SUMMARY_HTML"
                    file="internet_page/network_summary.html"
                    type="chrome_html" />
diff --git a/chrome/browser/stack_sampling_configuration.cc b/chrome/browser/stack_sampling_configuration.cc
index 63e1305d..51d6280 100644
--- a/chrome/browser/stack_sampling_configuration.cc
+++ b/chrome/browser/stack_sampling_configuration.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/stack_sampling_configuration.h"
 
+#include "base/rand_util.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/common/channel_info.h"
 #include "components/version_info/version_info.h"
@@ -20,8 +21,7 @@
 }  // namespace
 
 StackSamplingConfiguration::StackSamplingConfiguration()
-    // Disabled pending fixes for deadlock scenarios. https://crbug.com/528129.
-    : configuration_(PROFILE_DISABLED) {
+    : configuration_(GenerateConfiguration()) {
 }
 
 base::StackSamplingProfiler::SamplingParams
@@ -32,6 +32,7 @@
 
   switch (configuration_) {
     case PROFILE_DISABLED:
+    case PROFILE_CONTROL:
       params.initial_delay = base::TimeDelta::FromMilliseconds(0);
       params.sampling_interval = base::TimeDelta::FromMilliseconds(0);
       params.samples_per_burst = 0;
@@ -79,6 +80,10 @@
       group = "Disabled";
       break;
 
+    case PROFILE_CONTROL:
+      group = "Control";
+      break;
+
     case PROFILE_NO_SAMPLES:
       group = "NoSamples";
       break;
@@ -100,3 +105,41 @@
       "SyntheticStackProfilingConfiguration",
       group);
 }
+
+// static
+StackSamplingConfiguration::ProfileConfiguration
+StackSamplingConfiguration::GenerateConfiguration() {
+  // Enable the profiler in the intended ultimate production configuration for
+  // development/waterfall builds.
+  if (chrome::GetChannel() == version_info::Channel::UNKNOWN)
+    return PROFILE_10HZ;
+
+  struct Variation {
+    ProfileConfiguration config;
+    int weight;
+  };
+
+  // Generate a configuration according to the associated weights.
+  const Variation variations[] = {
+    { PROFILE_10HZ, 15},
+    { PROFILE_CONTROL, 15},
+    { PROFILE_DISABLED, 70}
+  };
+
+  int total_weight = 0;
+  for (const Variation& variation : variations)
+    total_weight += variation.weight;
+  DCHECK_EQ(100, total_weight);
+
+  int chosen = base::RandInt(0, total_weight - 1);  // Max is inclusive.
+  int cumulative_weight = 0;
+  for (const Variation& variation : variations) {
+    if (chosen >= cumulative_weight &&
+        chosen < cumulative_weight + variation.weight) {
+      return variation.config;
+    }
+    cumulative_weight += variation.weight;
+  }
+  NOTREACHED();
+  return PROFILE_DISABLED;
+}
diff --git a/chrome/browser/stack_sampling_configuration.h b/chrome/browser/stack_sampling_configuration.h
index e8c32fcf..9d18aa80 100644
--- a/chrome/browser/stack_sampling_configuration.h
+++ b/chrome/browser/stack_sampling_configuration.h
@@ -26,13 +26,15 @@
  private:
   enum ProfileConfiguration {
     PROFILE_DISABLED,
+    PROFILE_CONTROL,
     PROFILE_NO_SAMPLES,  // Run the profiler thread, but don't collect profiles.
     PROFILE_5HZ,
     PROFILE_10HZ,
-    PROFILE_100HZ,
-    PROFILE_COUNT = PROFILE_100HZ
+    PROFILE_100HZ
   };
 
+  static ProfileConfiguration GenerateConfiguration();
+
   const ProfileConfiguration configuration_;
 
   DISALLOW_COPY_AND_ASSIGN(StackSamplingConfiguration);
diff --git a/chrome/browser/ui/browser_dialogs_mac.cc b/chrome/browser/ui/browser_dialogs_mac.cc
index 1d67a32..cf79ad9 100644
--- a/chrome/browser/ui/browser_dialogs_mac.cc
+++ b/chrome/browser/ui/browser_dialogs_mac.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/ui/browser_dialogs.h"
 
 #include "base/command_line.h"
-#include "chrome/common/chrome_switches.cc"
+#include "chrome/common/chrome_switches.h"
 
 namespace chrome {
 
diff --git a/chrome/browser/ui/browser_tabstrip.cc b/chrome/browser/ui/browser_tabstrip.cc
index 995e0de..93f4a7bb 100644
--- a/chrome/browser/ui/browser_tabstrip.cc
+++ b/chrome/browser/ui/browser_tabstrip.cc
@@ -24,9 +24,10 @@
   // WebContents, but we want to include the time it takes to create the
   // WebContents object too.
   base::TimeTicks new_tab_start_time = base::TimeTicks::Now();
+  bool show_ntp = url.is_empty();
   chrome::NavigateParams params(browser,
-      url.is_empty() ? GURL(chrome::kChromeUINewTabURL) : url,
-      ui::PAGE_TRANSITION_TYPED);
+      show_ntp ? GURL(chrome::kChromeUINewTabURL) : url,
+      show_ntp ? ui::PAGE_TRANSITION_AUTO_TOPLEVEL : ui::PAGE_TRANSITION_TYPED);
   params.disposition = foreground ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
   params.tabstrip_index = idx;
   chrome::Navigate(&params);
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model.cc b/chrome/browser/ui/content_settings/content_setting_image_model.cc
index 94a2e08..d2099c8d 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_image_model.cc
@@ -15,11 +15,11 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/vector_icons_public.h"
 
 #if !defined(OS_MACOSX)
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/paint_vector_icon.h"
-#include "ui/gfx/vector_icons_public.h"
 #endif
 
 using content::WebContents;
@@ -90,19 +90,81 @@
 
 namespace {
 
-struct ContentSettingsTypeIdEntry {
+struct ContentSettingsImageDetails {
   ContentSettingsType type;
-  int id;
+  int blocked_icon_id;
+  gfx::VectorIconId vector_icon_id;
+  int blocked_tooltip_id;
+  int blocked_explanatory_text_id;
+  int accessed_icon_id;
+  int accessed_tooltip_id;
 };
 
-int GetIdForContentType(const ContentSettingsTypeIdEntry* entries,
-                        size_t num_entries,
-                        ContentSettingsType type) {
-  for (size_t i = 0; i < num_entries; ++i) {
-    if (entries[i].type == type)
-      return entries[i].id;
+static const ContentSettingsImageDetails kImageDetails[] = {
+    {CONTENT_SETTINGS_TYPE_COOKIES,
+     IDR_BLOCKED_COOKIES,
+     gfx::VectorIconId::COOKIE,
+     IDS_BLOCKED_COOKIES_TITLE,
+     0,
+     IDR_ACCESSED_COOKIES,
+     IDS_ACCESSED_COOKIES_TITLE},
+    {CONTENT_SETTINGS_TYPE_IMAGES,
+     IDR_BLOCKED_IMAGES,
+     gfx::VectorIconId::IMAGE,
+     IDS_BLOCKED_IMAGES_TITLE,
+     0,
+     0,
+     0},
+    {CONTENT_SETTINGS_TYPE_JAVASCRIPT,
+     IDR_BLOCKED_JAVASCRIPT,
+     gfx::VectorIconId::CODE,
+     IDS_BLOCKED_JAVASCRIPT_TITLE,
+     0,
+     0,
+     0},
+    {CONTENT_SETTINGS_TYPE_PLUGINS,
+     IDR_BLOCKED_PLUGINS,
+     gfx::VectorIconId::EXTENSION,
+     IDS_BLOCKED_PLUGINS_MESSAGE,
+     IDS_BLOCKED_PLUGIN_EXPLANATORY_TEXT,
+     0,
+     0},
+    {CONTENT_SETTINGS_TYPE_POPUPS,
+     IDR_BLOCKED_POPUPS,
+     gfx::VectorIconId::WEB,
+     IDS_BLOCKED_POPUPS_TOOLTIP,
+     IDS_BLOCKED_POPUPS_EXPLANATORY_TEXT,
+     0,
+     0},
+    {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT,
+     IDR_BLOCKED_MIXED_CONTENT,
+     gfx::VectorIconId::MIXED_CONTENT,
+     IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT,
+     0,
+     0,
+     0},
+    {CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
+     IDR_BLOCKED_PPAPI_BROKER,
+     gfx::VectorIconId::EXTENSION,
+     IDS_BLOCKED_PPAPI_BROKER_TITLE,
+     0,
+     IDR_BLOCKED_PPAPI_BROKER,
+     IDS_ALLOWED_PPAPI_BROKER_TITLE},
+    {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
+     IDR_BLOCKED_DOWNLOADS,
+     gfx::VectorIconId::FILE_DOWNLOAD,
+     IDS_BLOCKED_DOWNLOAD_TITLE,
+     IDS_BLOCKED_DOWNLOADS_EXPLANATION,
+     IDR_ALLOWED_DOWNLOADS,
+     IDS_ALLOWED_DOWNLOAD_TITLE},
+};
+
+const ContentSettingsImageDetails* GetImageDetails(ContentSettingsType type) {
+  for (const ContentSettingsImageDetails& image_details : kImageDetails) {
+    if (image_details.type == type)
+      return &image_details;
   }
-  return 0;
+  return nullptr;
 }
 
 }  // namespace
@@ -119,76 +181,11 @@
     return;
 
   ContentSettingsType type = get_content_settings_type();
-  static const ContentSettingsTypeIdEntry kBlockedIconIDs[] = {
-    {CONTENT_SETTINGS_TYPE_COOKIES, IDR_BLOCKED_COOKIES},
-    {CONTENT_SETTINGS_TYPE_IMAGES, IDR_BLOCKED_IMAGES},
-    {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDR_BLOCKED_JAVASCRIPT},
-    {CONTENT_SETTINGS_TYPE_PLUGINS, IDR_BLOCKED_PLUGINS},
-    {CONTENT_SETTINGS_TYPE_POPUPS, IDR_BLOCKED_POPUPS},
-    {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDR_BLOCKED_MIXED_CONTENT},
-    {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDR_BLOCKED_PPAPI_BROKER},
-    {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDR_BLOCKED_DOWNLOADS},
-  };
-  int icon_id =
-      GetIdForContentType(kBlockedIconIDs, arraysize(kBlockedIconIDs), type);
+  const ContentSettingsImageDetails* image_details = GetImageDetails(type);
 
-#if !defined(OS_MACOSX)
-  gfx::VectorIconId vector_icon_id = gfx::VectorIconId::VECTOR_ICON_NONE;
-  switch (type) {
-    case CONTENT_SETTINGS_TYPE_COOKIES:
-      vector_icon_id = gfx::VectorIconId::COOKIE;
-      break;
-    case CONTENT_SETTINGS_TYPE_IMAGES:
-      vector_icon_id = gfx::VectorIconId::IMAGE;
-      break;
-    case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
-      vector_icon_id = gfx::VectorIconId::CODE;
-      break;
-    case CONTENT_SETTINGS_TYPE_PLUGINS:
-      vector_icon_id = gfx::VectorIconId::EXTENSION;
-      break;
-    case CONTENT_SETTINGS_TYPE_POPUPS:
-      vector_icon_id = gfx::VectorIconId::WEB;
-      break;
-    case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT:
-      vector_icon_id = gfx::VectorIconId::MIXED_CONTENT;
-      break;
-    case CONTENT_SETTINGS_TYPE_PPAPI_BROKER:
-      vector_icon_id = gfx::VectorIconId::EXTENSION;
-      break;
-    case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
-      vector_icon_id = gfx::VectorIconId::FILE_DOWNLOAD;
-      break;
-    default:
-      // If we didn't find a vector icon ID we shouldn't have found an
-      // asset ID either.
-      DCHECK_EQ(0, icon_id);
-      break;
-  }
-#endif
-
-  static const ContentSettingsTypeIdEntry kBlockedTooltipIDs[] = {
-    {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_TITLE},
-    {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_TITLE},
-    {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_TITLE},
-    {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_MESSAGE},
-    {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_TOOLTIP},
-    {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT,
-        IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT},
-    {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_TITLE},
-    {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_TITLE},
-  };
-  int tooltip_id = GetIdForContentType(kBlockedTooltipIDs,
-                                       arraysize(kBlockedTooltipIDs), type);
-
-  static const ContentSettingsTypeIdEntry kBlockedExplanatoryTextIDs[] = {
-    {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_EXPLANATORY_TEXT},
-    {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGIN_EXPLANATORY_TEXT},
-    {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
-        IDS_BLOCKED_DOWNLOADS_EXPLANATION},
-  };
-  int explanation_id = GetIdForContentType(
-      kBlockedExplanatoryTextIDs, arraysize(kBlockedExplanatoryTextIDs), type);
+  int icon_id = image_details->blocked_icon_id;
+  int tooltip_id = image_details->blocked_tooltip_id;
+  int explanation_id = image_details->blocked_explanatory_text_id;
 
   // For plugins, don't show the animated explanation unless the plugin was
   // blocked despite the user's content settings being set to allow it (e.g.
@@ -220,20 +217,8 @@
         (map->GetDefaultContentSetting(type, NULL) != CONTENT_SETTING_BLOCK))
       return;
 
-    static const ContentSettingsTypeIdEntry kAccessedIconIDs[] = {
-      {CONTENT_SETTINGS_TYPE_COOKIES, IDR_ACCESSED_COOKIES},
-      {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDR_BLOCKED_PPAPI_BROKER},
-      {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDR_ALLOWED_DOWNLOADS},
-    };
-    icon_id = GetIdForContentType(kAccessedIconIDs, arraysize(kAccessedIconIDs),
-                                  type);
-    static const ContentSettingsTypeIdEntry kAccessedTooltipIDs[] = {
-      {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ACCESSED_COOKIES_TITLE},
-      {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_TITLE},
-      {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_TITLE},
-    };
-    tooltip_id = GetIdForContentType(
-        kAccessedTooltipIDs, arraysize(kAccessedTooltipIDs), type);
+    icon_id = image_details->accessed_icon_id;
+    tooltip_id = image_details->accessed_tooltip_id;
     explanation_id = 0;
   }
   set_visible(true);
@@ -242,12 +227,11 @@
     SetIconByResourceId(icon_id);
 #if !defined(OS_MACOSX)
   } else {
-    DCHECK(gfx::VectorIconId::VECTOR_ICON_NONE != vector_icon_id);
-
     if (type == CONTENT_SETTINGS_TYPE_PPAPI_BROKER) {
-      set_icon(GetIcon(vector_icon_id, gfx::VectorIconId::WARNING_BADGE));
+      set_icon(GetIcon(image_details->vector_icon_id,
+                       gfx::VectorIconId::WARNING_BADGE));
     } else {
-      SetIconByVectorId(vector_icon_id,
+      SetIconByVectorId(image_details->vector_icon_id,
                         content_settings->IsContentBlocked(type));
     }
 #endif
@@ -452,21 +436,18 @@
 ContentSettingImageModel*
     ContentSettingImageModel::CreateContentSettingImageModel(
     ContentSettingsType content_settings_type) {
-  switch (content_settings_type) {
-    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
-      return new ContentSettingGeolocationImageModel();
-    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
-      return new ContentSettingNotificationsImageModel();
-    case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS:
-      return new ContentSettingRPHImageModel();
-    case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
-    case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
-    case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
-      return new ContentSettingMediaImageModel(content_settings_type);
-    case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
-      return new ContentSettingMIDISysExImageModel();
-    default:
-      return new ContentSettingBlockedImageModel(content_settings_type);
+  if (content_settings_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
+    return new ContentSettingGeolocationImageModel();
+  } else if (content_settings_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
+    return new ContentSettingNotificationsImageModel();
+  } else if (content_settings_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) {
+    return new ContentSettingRPHImageModel();
+  } else if (content_settings_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM) {
+    return new ContentSettingMediaImageModel(content_settings_type);
+  } else if (content_settings_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
+    return new ContentSettingMIDISysExImageModel();
+  } else {
+    return new ContentSettingBlockedImageModel(content_settings_type);
   }
 }
 
diff --git a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
index 3e20da3..07b76f3 100644
--- a/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
+++ b/chrome/browser/ui/libgtk2ui/gtk2_ui.cc
@@ -1013,12 +1013,9 @@
   active_selection_fg_color_ =
       theme->GetSystemColor(
           ui::NativeTheme::kColorId_TextfieldSelectionColor);
-  inactive_selection_bg_color_ =
-      theme->GetSystemColor(
-          ui::NativeTheme::kColorId_TextfieldReadOnlyBackground);
-  inactive_selection_fg_color_ =
-      theme->GetSystemColor(
-          ui::NativeTheme::kColorId_TextfieldReadOnlyColor);
+
+  inactive_selection_bg_color_ = active_selection_bg_color_;
+  inactive_selection_fg_color_ = active_selection_fg_color_;
 
   colors_[ThemeProperties::COLOR_THROBBER_SPINNING] =
       theme->GetSystemColor(ui::NativeTheme::kColorId_ThrobberSpinningColor);
diff --git a/chrome/browser/ui/navigation_correction_tab_observer.cc b/chrome/browser/ui/navigation_correction_tab_observer.cc
index 6be6a9f..a943d401 100644
--- a/chrome/browser/ui/navigation_correction_tab_observer.cc
+++ b/chrome/browser/ui/navigation_correction_tab_observer.cc
@@ -15,12 +15,10 @@
 #include "components/google/core/browser/google_util.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "google_apis/google_api_keys.h"
 
 using content::RenderFrameHost;
-using content::RenderViewHost;
 using content::WebContents;
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(NavigationCorrectionTabObserver);
@@ -65,16 +63,20 @@
 ////////////////////////////////////////////////////////////////////////////////
 // WebContentsObserver overrides
 
-void NavigationCorrectionTabObserver::RenderViewCreated(
-    RenderViewHost* render_view_host) {
-  UpdateNavigationCorrectionInfo(render_view_host);
+void NavigationCorrectionTabObserver::RenderFrameCreated(
+    RenderFrameHost* render_frame_host) {
+  // Ignore subframe creation - only main frame error pages can request and
+  // display nagivation correction information.
+  if (render_frame_host->GetParent())
+    return;
+  UpdateNavigationCorrectionInfo(render_frame_host);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Internal helpers
 
 void NavigationCorrectionTabObserver::OnGoogleURLUpdated() {
-  UpdateNavigationCorrectionInfo(web_contents()->GetRenderViewHost());
+  UpdateNavigationCorrectionInfo(web_contents()->GetMainFrame());
 }
 
 GURL NavigationCorrectionTabObserver::GetNavigationCorrectionURL() const {
@@ -89,15 +91,14 @@
 }
 
 void NavigationCorrectionTabObserver::OnEnabledChanged() {
-  UpdateNavigationCorrectionInfo(web_contents()->GetRenderViewHost());
+  UpdateNavigationCorrectionInfo(web_contents()->GetMainFrame());
 }
 
 void NavigationCorrectionTabObserver::UpdateNavigationCorrectionInfo(
-    RenderViewHost* rvh) {
-  RenderFrameHost* rfh = rvh->GetMainFrame();
+    RenderFrameHost* render_frame_host) {
   GURL google_base_url(UIThreadSearchTermsData(profile_).GoogleBaseURLValue());
-  rfh->Send(new ChromeViewMsg_SetNavigationCorrectionInfo(
-      rfh->GetRoutingID(),
+  render_frame_host->Send(new ChromeViewMsg_SetNavigationCorrectionInfo(
+      render_frame_host->GetRoutingID(),
       GetNavigationCorrectionURL(),
       google_util::GetGoogleLocale(g_browser_process->GetApplicationLocale()),
       google_util::GetGoogleCountryCode(google_base_url),
diff --git a/chrome/browser/ui/navigation_correction_tab_observer.h b/chrome/browser/ui/navigation_correction_tab_observer.h
index 85a2095..cc562f9 100644
--- a/chrome/browser/ui/navigation_correction_tab_observer.h
+++ b/chrome/browser/ui/navigation_correction_tab_observer.h
@@ -30,7 +30,7 @@
   friend class content::WebContentsUserData<NavigationCorrectionTabObserver>;
 
   // content::WebContentsObserver overrides:
-  void RenderViewCreated(content::RenderViewHost* render_view_host) override;
+  void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
 
   // Internal helpers ----------------------------------------------------------
 
@@ -45,7 +45,8 @@
   void OnEnabledChanged();
 
   // Updates the renderer's navigation correction service configuration.
-  void UpdateNavigationCorrectionInfo(content::RenderViewHost* rvh);
+  void UpdateNavigationCorrectionInfo(
+      content::RenderFrameHost* render_frame_host);
 
   Profile* profile_;
   PrefChangeRegistrar pref_change_registrar_;
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index 50c520c8..d354428c 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -74,12 +74,14 @@
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/page_transition_types.h"
+#include "ui/base/resource/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/theme_provider.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/compositor/paint_recorder.h"
 #include "ui/gfx/animation/slide_animation.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/favicon_size.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/text_constants.h"
 #include "ui/gfx/text_elider.h"
@@ -145,8 +147,8 @@
 static const int kSeparatorMargin = 1;
 
 // Width of the separator between the recently bookmarked button and the
-// overflow indicator.
-static const int kSeparatorWidth = 4;
+// overflow indicator, indexed by MD mode.
+static const int kSeparatorWidth[] = {4, 9, 9};
 
 // Starting x-coordinate of the separator line within a separator.
 static const int kSeparatorStartX = 2;
@@ -347,8 +349,7 @@
 class OverflowButton : public views::MenuButton {
  public:
   explicit OverflowButton(BookmarkBarView* owner)
-      : MenuButton(NULL, base::string16(), owner, false),
-        owner_(owner) {}
+      : MenuButton(NULL, base::string16(), owner, false), owner_(owner) {}
 
   bool OnMousePressed(const ui::MouseEvent& e) override {
     owner_->StopThrobbing(true);
@@ -475,20 +476,40 @@
   ~ButtonSeparatorView() override {}
 
   void OnPaint(gfx::Canvas* canvas) override {
-    PaintVerticalDivider(
-        canvas,
-        kSeparatorStartX,
-        height(),
-        1,
-        kEdgeDividerColor,
-        kMiddleDividerColor,
-        GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR));
+    if (ui::MaterialDesignController::IsModeMaterial()) {
+      // 1px wide at all scale factors. If there is an uneven amount of padding
+      // left over, place the extra pixel on the outside, i.e. away from the
+      // "Other bookmarks" folder.
+      const float scale = canvas->SaveAndUnscale();
+      const gfx::RectF scaled_bounds =
+          gfx::ScaleRect(gfx::RectF(bounds()), scale);
+
+      const int kLineThickness = 1;
+      const float fractional_x = (scaled_bounds.width() - kLineThickness) / 2.f;
+      const int x = base::i18n::IsRTL() ? std::floor(fractional_x)
+                                        : std::ceil(fractional_x);
+
+      const int height = gfx::kFaviconSize * scale;
+      const int top_y = (scaled_bounds.height() - height) / 2;
+      canvas->DrawLine(
+          gfx::Point(x, top_y), gfx::Point(x, top_y + height),
+          SkColorSetA(GetThemeProvider()->GetColor(
+                          ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON),
+                      0x4D));
+      canvas->Restore();
+    } else {
+      PaintVerticalDivider(
+          canvas, kSeparatorStartX, height(), 1, kEdgeDividerColor,
+          kMiddleDividerColor,
+          GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR));
+    }
   }
 
   gfx::Size GetPreferredSize() const override {
     // We get the full height of the bookmark bar, so that the height returned
     // here doesn't matter.
-    return gfx::Size(kSeparatorWidth, 1);
+    return gfx::Size(kSeparatorWidth[ui::MaterialDesignController::GetMode()],
+                     1);
   }
 
   void GetAccessibleState(ui::AXViewState* state) override {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
index 95ce226..3e142b44 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -6,7 +6,6 @@
 
 #include <string>
 
-#include "base/auto_reset.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
@@ -28,7 +27,6 @@
 #include "ui/resources/grit/ui_resources.h"
 #include "ui/views/controls/button/label_button_border.h"
 #include "ui/views/controls/menu/menu_controller.h"
-#include "ui/views/controls/menu/menu_model_adapter.h"
 #include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/mouse_constants.h"
 #include "ui/views/resources/grit/views_resources.h"
@@ -47,9 +45,6 @@
 // safe to have this be a global singleton.
 ToolbarActionView* context_menu_owner = nullptr;
 
-// The callback to call directly before showing the context menu.
-ToolbarActionView::ContextMenuCallback* context_menu_callback = nullptr;
-
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -65,7 +60,6 @@
       delegate_(delegate),
       called_register_command_(false),
       wants_to_run_(false),
-      menu_(nullptr),
       weak_factory_(this) {
   set_id(VIEW_ID_BROWSER_ACTION);
   view_controller_->SetDelegate(this);
@@ -199,11 +193,6 @@
   return GetImage(views::Button::STATE_NORMAL);
 }
 
-void ToolbarActionView::set_context_menu_callback_for_testing(
-    base::Callback<void(ToolbarActionView*)>* callback) {
-  context_menu_callback = callback;
-}
-
 views::View* ToolbarActionView::GetAsView() {
   return this;
 }
@@ -220,7 +209,7 @@
 }
 
 bool ToolbarActionView::IsMenuRunning() const {
-  return menu_ != nullptr;
+  return menu_runner_.get() != nullptr;
 }
 
 content::WebContents* ToolbarActionView::GetCurrentWebContents() const {
@@ -280,6 +269,7 @@
 
   DCHECK(visible());  // We should never show a context menu for a hidden item.
   DCHECK(!context_menu_owner);
+  context_menu_owner = this;
 
   gfx::Point screen_loc;
   ConvertPointToScreen(this, &screen_loc);
@@ -295,25 +285,18 @@
       delegate_->GetOverflowReferenceView()->GetWidget() :
       GetWidget();
 
-  views::MenuModelAdapter adapter(context_menu_model);
-  views::MenuItemView* menu_root = adapter.CreateMenu();
+  menu_runner_.reset(new views::MenuRunner(context_menu_model, run_types));
 
-  {
-    base::AutoReset<views::MenuItemView*> menu_resetter(&menu_, menu_root);
-    base::AutoReset<ToolbarActionView*> menu_owner_resetter(&context_menu_owner,
-                                                            this);
-
-    views::MenuRunner menu_runner(menu_, run_types);
-
-    if (context_menu_callback)
-      context_menu_callback->Run(this);
-    if (menu_runner.RunMenuAt(parent, this, gfx::Rect(screen_loc, size()),
+  if (menu_runner_->RunMenuAt(parent,
+                              this,
+                              gfx::Rect(screen_loc, size()),
                               views::MENU_ANCHOR_TOPLEFT,
                               source_type) == views::MenuRunner::MENU_DELETED) {
-      return;
-    }
+    return;
   }
 
+  context_menu_owner = nullptr;
+  menu_runner_.reset();
   view_controller_->OnContextMenuClosed();
 
   // If another extension action wants to show its context menu, allow it to.
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.h b/chrome/browser/ui/views/toolbar/toolbar_action_view.h
index 8555af7..19db601bd 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_TOOLBAR_ACTION_VIEW_H_
 #define CHROME_BROWSER_UI_VIEWS_TOOLBAR_TOOLBAR_ACTION_VIEW_H_
 
-#include "base/callback.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_action_view_delegate_views.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -27,7 +26,7 @@
 }
 
 namespace views {
-class MenuItemView;
+class MenuRunner;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -99,14 +98,6 @@
 
   bool wants_to_run_for_testing() const { return wants_to_run_; }
 
-  using ContextMenuCallback = base::Callback<void(ToolbarActionView*)>;
-  // Set a callback to be called directly before the context menu is shown.
-  // The toolbar action opening the menu will be passed in.
-  static void set_context_menu_callback_for_testing(
-      ContextMenuCallback* callback);
-
-  views::MenuItemView* menu_for_testing() { return menu_; }
-
  private:
   // views::MenuButton:
   gfx::Size GetPreferredSize() const override;
@@ -155,9 +146,8 @@
   // tab.
   bool wants_to_run_;
 
-  // The root MenuItemView for the context menu, or null if no menu is being
-  // shown.
-  views::MenuItemView* menu_;
+  // Responsible for running the menu.
+  scoped_ptr<views::MenuRunner> menu_runner_;
 
   // If non-null, this is the next toolbar action context menu that wants to run
   // once the current owner (this one) is done.
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
index 56d34ce0..c91b0f1 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
@@ -3,12 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "chrome/browser/extensions/extension_action_test_util.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
-#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/ui/extensions/extension_action_view_controller.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -21,26 +17,18 @@
 #include "chrome/test/base/interactive_test_utils.h"
 #include "extensions/common/feature_switch.h"
 #include "extensions/test/extension_test_message_listener.h"
-#include "ui/views/controls/menu/menu_controller.h"
-#include "ui/views/controls/menu/menu_item_view.h"
-#include "ui/views/controls/menu/submenu_view.h"
 
 namespace {
 
-WrenchToolbarButton* GetWrenchButtonFromBrowser(Browser* browser) {
-  return BrowserView::GetBrowserViewForBrowser(browser)
-      ->toolbar()
-      ->app_menu_button();
-}
-
 // Tests clicking on an overflowed toolbar action. This is called when the app
 // menu is open, and handles actually clicking on the action.
-// |button| specifies the mouse button to click with.
 void TestOverflowedToolbarAction(Browser* browser,
-                                 ui_controls::MouseButton button,
                                  const base::Closure& quit_closure) {
   // A bunch of plumbing to safely get at the overflowed toolbar action.
-  WrenchToolbarButton* app_menu_button = GetWrenchButtonFromBrowser(browser);
+  WrenchToolbarButton* app_menu_button =
+      BrowserView::GetBrowserViewForBrowser(browser)
+          ->toolbar()
+          ->app_menu_button();
   EXPECT_TRUE(app_menu_button->IsMenuShowing());
   WrenchMenu* app_menu = app_menu_button->app_menu_for_testing();
   ASSERT_TRUE(app_menu);
@@ -54,81 +42,12 @@
       overflow_container->GetToolbarActionViewAt(0);
   EXPECT_TRUE(action_view->visible());
 
-  // Click on the toolbar action to activate it.
+  // Left click on the toolbar action to activate it.
   gfx::Point action_view_loc =
       test::GetCenterInScreenCoordinates(action_view);
   ui_controls::SendMouseMove(action_view_loc.x(), action_view_loc.y());
   ui_controls::SendMouseEventsNotifyWhenDone(
-      button, ui_controls::DOWN | ui_controls::UP, quit_closure);
-}
-
-// Tests the context menu of an overflowed action.
-void TestWhileContextMenuOpen(bool* did_test_while_menu_open,
-                              Browser* browser,
-                              ToolbarActionView* context_menu_action) {
-  *did_test_while_menu_open = true;
-
-  views::MenuItemView* menu_root = context_menu_action->menu_for_testing();
-  ASSERT_TRUE(menu_root);
-  ASSERT_TRUE(menu_root->GetSubmenu());
-  EXPECT_TRUE(menu_root->GetSubmenu()->IsShowing());
-  views::MenuItemView* first_menu_item =
-      menu_root->GetSubmenu()->GetMenuItemAt(0);
-  ASSERT_TRUE(first_menu_item);
-
-  // Make sure we're showing the right context menu.
-  EXPECT_EQ(base::UTF8ToUTF16("Browser Action Popup"),
-            first_menu_item->title());
-  EXPECT_TRUE(first_menu_item->enabled());
-
-  // Get the overflow container.
-  WrenchToolbarButton* app_menu_button = GetWrenchButtonFromBrowser(browser);
-  WrenchMenu* app_menu = app_menu_button->app_menu_for_testing();
-  ASSERT_TRUE(app_menu);
-  ExtensionToolbarMenuView* menu_view =
-      app_menu->extension_toolbar_for_testing();
-  ASSERT_TRUE(menu_view);
-  BrowserActionsContainer* overflow_container =
-      menu_view->container_for_testing();
-  ASSERT_TRUE(overflow_container);
-
-  // Get the first action on the second row of the overflow container.
-  int second_row_index = overflow_container->toolbar_actions_bar()
-                             ->platform_settings()
-                             .icons_per_overflow_menu_row;
-  ToolbarActionView* second_row_action =
-      overflow_container->GetToolbarActionViewAt(second_row_index);
-
-  EXPECT_TRUE(second_row_action->visible());
-  EXPECT_TRUE(second_row_action->enabled());
-
-  gfx::Point action_view_loc =
-      test::GetCenterInScreenCoordinates(second_row_action);
-  gfx::Point action_view_loc_in_menu_item_bounds = action_view_loc;
-  views::View::ConvertPointFromScreen(first_menu_item,
-                                      &action_view_loc_in_menu_item_bounds);
-  // Regression test for crbug.com/538414: The first menu item is overlapping
-  // the second row action button. With crbug.com/538414, the click would go to
-  // the menu button, instead of the menu item.
-  EXPECT_TRUE(
-      first_menu_item->HitTestPoint(action_view_loc_in_menu_item_bounds));
-
-  // Click on the first menu item (which shares bounds, but overlaps, the second
-  // row action).
-  ui_controls::SendMouseMove(action_view_loc.x(), action_view_loc.y());
-  ui_controls::SendMouseEventsNotifyWhenDone(
-      ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP, base::Closure());
-
-  // Test resumes in the main test body.
-}
-
-// Posts a task to test the context menu.
-void OnContextMenuWillShow(bool* did_test_while_menu_open,
-                           Browser* browser,
-                           ToolbarActionView* toolbar_action_view) {
-  base::MessageLoop::current()->task_runner()->PostTask(
-      FROM_HERE, base::Bind(&TestWhileContextMenuOpen, did_test_while_menu_open,
-                            browser, toolbar_action_view));
+      ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP, quit_closure);
 }
 
 }  // namespace
@@ -187,7 +106,10 @@
   // opened. Listen for the message.
   ExtensionTestMessageListener listener("Popup opened", false);
 
-  WrenchToolbarButton* app_menu_button = GetWrenchButtonFromBrowser(browser());
+  WrenchToolbarButton* app_menu_button =
+      BrowserView::GetBrowserViewForBrowser(browser())
+          ->toolbar()
+          ->app_menu_button();
 
   // Click on the app button.
   gfx::Point app_button_loc =
@@ -195,9 +117,9 @@
   base::RunLoop loop;
   ui_controls::SendMouseMove(app_button_loc.x(), app_button_loc.y());
   ui_controls::SendMouseEventsNotifyWhenDone(
-      ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
-      base::Bind(&TestOverflowedToolbarAction, browser(), ui_controls::LEFT,
-                 loop.QuitClosure()));
+      ui_controls::LEFT,
+      ui_controls::DOWN | ui_controls::UP,
+      base::Bind(&TestOverflowedToolbarAction, browser(), loop.QuitClosure()));
   loop.Run();
   // The app menu should no longer be showing.
   EXPECT_FALSE(app_menu_button->IsMenuShowing());
@@ -206,76 +128,6 @@
   listener.WaitUntilSatisfied();
 }
 
-#if defined(USE_OZONE)
-// ozone bringup - http://crbug.com/401304
-#define MAYBE_TestContextMenuOnOverflowedAction \
-  DISABLED_TestContextMenuOnOverflowedAction
-#else
-#define MAYBE_TestContextMenuOnOverflowedAction \
-  TestContextMenuOnOverflowedAction
-#endif
-// Tests the context menus of overflowed extension actions.
-IN_PROC_BROWSER_TEST_F(ToolbarActionViewInteractiveUITest,
-                       MAYBE_TestContextMenuOnOverflowedAction) {
-  views::MenuController::TurnOffMenuSelectionHoldForTest();
-
-  // Load an extension that has a home page (important for the context menu's
-  // first item being enabled).
-  ASSERT_TRUE(LoadExtension(
-      test_data_dir_.AppendASCII("ui").AppendASCII("browser_action_popup")));
-  base::RunLoop().RunUntilIdle();  // Ensure the extension is fully loaded.
-
-  // Aaaannnnd... Load a bunch of other extensions so that the overflow menu
-  // is spread across multiple rows.
-  for (int i = 0; i < 15; ++i) {
-    scoped_refptr<const extensions::Extension> extension =
-        extensions::extension_action_test_util::CreateActionExtension(
-            base::IntToString(i),
-            extensions::extension_action_test_util::BROWSER_ACTION);
-    extension_service()->AddExtension(extension.get());
-  }
-
-  ASSERT_EQ(16u, browser()
-                     ->window()
-                     ->GetToolbarActionsBar()
-                     ->toolbar_actions_unordered()
-                     .size());
-
-  // Reduce visible count to 0 so that all actions are overflowed.
-  ToolbarActionsModel::Get(profile())->SetVisibleIconCount(0);
-
-  // Set a callback for the context menu showing.
-  bool did_test_while_menu_open = false;
-  base::Callback<void(ToolbarActionView*)> context_menu_callback(
-      base::Bind(&OnContextMenuWillShow, &did_test_while_menu_open, browser()));
-  ToolbarActionView::set_context_menu_callback_for_testing(
-      &context_menu_callback);
-
-  WrenchToolbarButton* app_menu_button = GetWrenchButtonFromBrowser(browser());
-  // Click on the app button, and then right-click on the first toolbar action.
-  gfx::Point app_button_loc =
-      test::GetCenterInScreenCoordinates(app_menu_button);
-  base::RunLoop loop;
-  ui_controls::SendMouseMove(app_button_loc.x(), app_button_loc.y());
-  ui_controls::SendMouseEventsNotifyWhenDone(
-      ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
-      base::Bind(&TestOverflowedToolbarAction, browser(), ui_controls::RIGHT,
-                 loop.QuitClosure()));
-  loop.Run();
-
-  // Test is continued first in TestOverflowedToolbarAction() to right click on
-  // the action, followed by OnContextMenuWillShow() and
-  // TestWhileContextMenuOpen().
-
-  // Make sure we did all the expected tests.
-  EXPECT_TRUE(did_test_while_menu_open);
-
-  // We should have navigated to the extension's home page, which is google.com.
-  EXPECT_EQ(
-      GURL("https://www.google.com/"),
-      browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL());
-}
-
 // Tests that clicking on the toolbar action a second time when the action is
 // already open results in closing the popup, and doesn't re-open it.
 IN_PROC_BROWSER_TEST_F(ToolbarActionViewInteractiveUITest,
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index a2ade15..7740a5db 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1924,8 +1924,6 @@
       'browser/net/chrome_url_request_context_getter.h',
       'browser/net/connect_interceptor.cc',
       'browser/net/connect_interceptor.h',
-      'browser/net/cookie_store_util.cc',
-      'browser/net/cookie_store_util.h',
       'browser/net/crl_set_fetcher.cc',
       'browser/net/crl_set_fetcher.h',
       'browser/net/dns_probe_runner.cc',
@@ -2047,12 +2045,6 @@
       'browser/net/nss_context.h',
       'browser/net/nss_context_chromeos.cc',
       'browser/net/nss_context_linux.cc',
-      'third_party/mozilla_security_manager/nsNSSCertHelper.cpp',
-      'third_party/mozilla_security_manager/nsNSSCertHelper.h',
-      'third_party/mozilla_security_manager/nsNSSCertificate.cpp',
-      'third_party/mozilla_security_manager/nsNSSCertificate.h',
-      'third_party/mozilla_security_manager/nsUsageArrayHelper.cpp',
-      'third_party/mozilla_security_manager/nsUsageArrayHelper.h',
     ],
     'chrome_browser_password_manager_sources': [
       'browser/password_manager/chrome_password_manager_client.cc',
@@ -3218,6 +3210,7 @@
             '../components/components.gyp:autofill_content_browser',
             '../components/components.gyp:browsing_data',
             '../components/components.gyp:certificate_reporting',
+            '../components/components.gyp:cookie_config',
             '../components/components.gyp:data_reduction_proxy_content_browser',
             '../components/components.gyp:data_use_measurement_content',
             '../components/components.gyp:devtools_discovery',
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 098eae3..65fdc7a 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -851,6 +851,8 @@
       'browser/extensions/unpacked_installer.h',
       'browser/extensions/updater/chrome_extension_downloader_factory.cc',
       'browser/extensions/updater/chrome_extension_downloader_factory.h',
+      'browser/extensions/updater/chrome_update_client_config.cc',
+      'browser/extensions/updater/chrome_update_client_config.h',
       'browser/extensions/updater/extension_updater.cc',
       'browser/extensions/updater/extension_updater.h',
       'browser/extensions/user_script_listener.cc',
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index de1cde48..15a442a 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -595,6 +595,15 @@
           ],
         }],
         ['use_nss_certs == 1', {
+          'sources': [
+            # GN version: //chrome/third_party/mozilla_security_manager
+            'third_party/mozilla_security_manager/nsNSSCertHelper.cpp',
+            'third_party/mozilla_security_manager/nsNSSCertHelper.h',
+            'third_party/mozilla_security_manager/nsNSSCertificate.cpp',
+            'third_party/mozilla_security_manager/nsNSSCertificate.h',
+            'third_party/mozilla_security_manager/nsUsageArrayHelper.cpp',
+            'third_party/mozilla_security_manager/nsUsageArrayHelper.h',
+          ],
           'dependencies': [
             '../build/linux/system.gyp:ssl',
           ],
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 2d819521..e1f8f3a 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -47,10 +47,6 @@
   ]
 
   public_deps = [
-    "//chrome/common:constants",
-    "//chrome/common/safe_browsing:proto",
-  ]
-  deps = [
     "//base:base",
     "//base:i18n",
     "//base:prefs",
@@ -58,12 +54,17 @@
     "//chrome:resources",
     "//chrome:strings",
     "//chrome/app/theme:theme_resources",
+    "//chrome/common:constants",
+    "//chrome/common/safe_browsing:proto",
     "//chrome/common/variations:fieldtrial_testing_config",
     "//chrome/installer/util",
     "//components/cloud_devices/common",
     "//components/component_updater",
     "//components/content_settings/core/common",
     "//components/crash/core/common",
+    "//components/data_reduction_proxy/content/common",
+    "//components/dom_distiller/core",
+    "//components/error_page/common",
     "//components/favicon_base",
     "//components/gcm_driver/common",
     "//components/json_schema",
@@ -79,10 +80,20 @@
     "//content/public/common",
     "//crypto",
     "//extensions/common:common_constants",
+    "//gin",
+    "//google_apis",
+    "//gpu/command_buffer/service",
+    "//gpu/config",
     "//net",
+    "//ppapi/shared_impl",
     "//skia",
     "//third_party/icu",
     "//third_party/zlib:zip",
+    "//ui/accessibility",
+    "//ui/base",
+    "//ui/gfx/ipc",
+    "//ui/gl",
+    "//ui/message_center",
     "//ui/resources:resources",
     "//url",
   ]
@@ -98,8 +109,9 @@
     ]
   } else {
     # Non-iOS.
-    deps += [
+    public_deps += [
       ":mojo_bindings",
+      "//chrome/common/net",
       "//components/visitedlink/common",
       "//components/autofill/content/common",
       "//components/autofill/core/common",
@@ -110,11 +122,8 @@
       "//media",
       "//ipc",
       "//third_party/re2",
-      "//third_party/widevine/cdm:version_h",
-    ]
-    public_deps += [
-      "//chrome/common/net",
       "//third_party/mojo/src/mojo/public/cpp/bindings",
+      "//third_party/widevine/cdm:version_h",
     ]
   }
 
@@ -122,7 +131,7 @@
     sources += rebase_path(gypi_values.chrome_common_extensions_sources,
                            ".",
                            "//chrome")
-    deps += [
+    public_deps += [
       "//device/usb",
       "//chrome/common/extensions/api",
       "//extensions/common",
@@ -130,6 +139,9 @@
       "//extensions:extensions_resources",
       "//extensions/strings",
       "//media/cast:net",
+
+      # This dependency is for a header used only by extensions code.
+      "//ui/keyboard:keyboard_with_content",
     ]
     if (is_chromeos) {
       sources +=
@@ -142,7 +154,7 @@
   if (is_win || is_mac) {
     sources +=
         rebase_path(gypi_values.chrome_common_win_mac_sources, ".", "//chrome")
-    deps += [ "//breakpad:client" ]
+    public_deps += [ "//breakpad:client" ]
   }
   if (is_win || is_mac || is_chromeos) {
     sources += rebase_path(gypi_values.chrome_common_networking_private_sources,
@@ -150,21 +162,24 @@
                            "//chrome")
 
     # networking_private_crypto.cc depends on boringssl.
-    deps += [ "//third_party/boringssl" ]
+    public_deps += [ "//third_party/boringssl" ]
   }
   if (is_mac) {
     sources +=
         rebase_path(gypi_values.chrome_common_mac_sources, ".", "//chrome")
-    deps += [ ":app_mode_app_support" ]
+    public_deps += [ ":app_mode_app_support" ]
+  }
+  if (is_chromeos) {
+    public_deps += [ "//chromeos" ]
   }
 
   if (enable_nacl) {
-    deps += [ "//components/nacl:nacl_common" ]
+    public_deps += [ "//components/nacl:nacl_common" ]
   }
 
   # Printing.
   if (enable_basic_printing || enable_print_preview) {
-    deps += [
+    public_deps += [
       "//components/printing/common",
       "//printing",
     ]
@@ -207,7 +222,7 @@
   }
 
   if (is_win) {
-    deps += [
+    public_deps += [
       "//components/dom_distiller/core",  # Needed by chrome_content_client.cc.
       "//third_party/wtl",
     ]
@@ -219,7 +234,7 @@
 
   if (is_mac) {
     sources -= [ "channel_info_posix.cc" ]
-    deps += [
+    public_deps += [
       "//third_party/mach_override",
       "//third_party/google_toolbox_for_mac",
     ]
@@ -232,7 +247,7 @@
       "ppapi_utils.cc",
       "ppapi_utils.h",
     ]
-    deps += [ "//third_party/adobe/flash:flapper_version_h" ]
+    public_deps += [ "//third_party/adobe/flash:flapper_version_h" ]
   }
   if (enable_plugins && enable_extensions) {
     sources += [
@@ -244,7 +259,7 @@
     sources -= [ "media/webrtc_logging_messages.h" ]
   }
   if (enable_configuration_policy) {
-    deps += [ "//components/policy" ]
+    public_deps += [ "//components/policy" ]
   }
 
   if (safe_browsing_mode == 1) {
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index c0d6265..4c24a3a1 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -68,7 +68,7 @@
 
 #if defined(ENABLE_PLUGINS)
 #include "content/public/common/pepper_plugin_info.h"
-#include "flapper_version.h"  // In SHARED_INTERMEDIATE_DIR.
+#include "flapper_version.h"  // nogncheck  In SHARED_INTERMEDIATE_DIR.
 #include "ppapi/shared_impl/ppapi_permissions.h"
 #endif
 
diff --git a/chrome/common/chrome_paths_android.cc b/chrome/common/chrome_paths_android.cc
index a78b48d..9184418 100644
--- a/chrome/common/chrome_paths_android.cc
+++ b/chrome/common/chrome_paths_android.cc
@@ -7,7 +7,6 @@
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/path_service.h"
-#include "content/public/common/content_switches.h"
 
 namespace chrome {
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 5e53039..a0f360d 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -13,10 +13,6 @@
 // Don't add more switch files here. This is linked into some places like the
 // installer where dependencies should be limited. Instead, have files
 // directly include your switch file.
-//
-// TODO(brettw) delete content_switches.h include and make callers include that
-// file manually if they need a content switch.
-#include "content/public/common/content_switches.h"
 
 namespace switches {
 
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index 3cd3cd4..8b2aabf 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -16,10 +16,12 @@
 #include "content/public/common/content_switches.h"
 #include "ipc/ipc_switches.h"
 
+// Breakpad dependencies exist only on Windows and Mac desktop. Exclude them
+// from "gn check" to avoid failures on Linux (it doesn't understand ifdefs).
 #if defined(OS_MACOSX)
-#include "breakpad/src/common/simple_string_dictionary.h"
+#include "breakpad/src/common/simple_string_dictionary.h"  // nogncheck
 #elif defined(OS_WIN)
-#include "breakpad/src/client/windows/common/ipc_protocol.h"
+#include "breakpad/src/client/windows/common/ipc_protocol.h"  // nogncheck
 #elif defined(OS_CHROMEOS)
 #include "chrome/common/chrome_switches.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
diff --git a/chrome/common/extensions/extension_process_policy.h b/chrome/common/extensions/extension_process_policy.h
index 7231c0f8..2323483 100644
--- a/chrome/common/extensions/extension_process_policy.h
+++ b/chrome/common/extensions/extension_process_policy.h
@@ -5,12 +5,12 @@
 #ifndef CHROME_COMMON_EXTENSIONS_EXTENSION_PROCESS_POLICY_H_
 #define CHROME_COMMON_EXTENSIONS_EXTENSION_PROCESS_POLICY_H_
 
-class ExtensionSet;
 class GURL;
 
 namespace extensions {
 
 class Extension;
+class ExtensionSet;
 
 // Returns the extension for the given URL.  Excludes extension objects for
 // bookmark apps, which do not use the app process model.
diff --git a/chrome/common/net/BUILD.gn b/chrome/common/net/BUILD.gn
index 70e6b72..a6d51519 100644
--- a/chrome/common/net/BUILD.gn
+++ b/chrome/common/net/BUILD.gn
@@ -19,6 +19,7 @@
 
   deps = [
     "//base",
+    "//base:i18n",
     "//chrome:resources",
     "//chrome:strings",
     "//components/url_formatter",
@@ -44,7 +45,12 @@
   }
 
   if (use_nss_certs) {
-    deps += [ "//crypto:platform" ]
+    deps += [
+      "//chrome/third_party/mozilla_security_manager",
+      "//crypto:platform",
+    ]
+    allow_circular_includes_from =
+        [ "//chrome/third_party/mozilla_security_manager" ]
   } else {
     sources -= [ "x509_certificate_model_nss.cc" ]
   }
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 46a7f9e9..d454384f 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1306,14 +1306,6 @@
 const char kStabilityPluginCrashes[] = "crashes";
 const char kStabilityPluginLoadingErrors[] = "loading_errors";
 
-// The keys below are strictly increasing counters over the lifetime of
-// a chrome installation. They are (optionally) sent up to the uninstall
-// survey in the event of uninstallation.
-const char kUninstallLastLaunchTimeSec[] =
-    "uninstall_metrics.last_launch_time_sec";
-const char kUninstallLastObservedRunTimeSec[] =
-    "uninstall_metrics.last_observed_running_time_sec";
-
 // String containing the version of Chrome for which Chrome will not prompt the
 // user about setting Chrome as the default browser.
 const char kBrowserSuppressDefaultBrowserPrompt[] =
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index b9bc4e88..400ac45f 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -454,9 +454,6 @@
 extern const char kStabilityPluginCrashes[];
 extern const char kStabilityPluginLoadingErrors[];
 
-extern const char kUninstallLastLaunchTimeSec[];
-extern const char kUninstallLastObservedRunTimeSec[];
-
 extern const char kBrowserSuppressDefaultBrowserPrompt[];
 
 extern const char kBrowserWindowPlacement[];
diff --git a/chrome/installer/util/delete_after_reboot_helper.cc b/chrome/installer/util/delete_after_reboot_helper.cc
index bc7cd2b..c9cf0fe7 100644
--- a/chrome/installer/util/delete_after_reboot_helper.cc
+++ b/chrome/installer/util/delete_after_reboot_helper.cc
@@ -253,10 +253,10 @@
   DWORD last_error = ::GetLastError();
   DLOG_IF(WARNING, length == 0 && last_error != ERROR_PATH_NOT_FOUND)
       << __FUNCTION__ << " gle=" << last_error;
-  if (length == 0) {
-    // GetShortPathName fails if the path is no longer present. Instead of
-    // returning an empty string, just return the original string. This will
-    // serve our purposes.
+  if ((length == 0) || (length > MAX_PATH)) {
+    // GetShortPathName fails if the path is no longer present or cannot be
+    // put in the size buffer provided.  Instead of returning an empty string,
+    // just return the original string.  This will serve our purposes.
     return path;
   }
 
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index a753f80..37ecbcfc 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -1307,10 +1307,10 @@
     const base::FilePath& chrome_exe,
     const wchar_t* const* protocols,
     size_t num_protocols) {
-  // Get its short (8.3) form.
-  base::string16 short_app_path;
-  if (!ShortNameFromPath(chrome_exe, &short_app_path))
-    return ShellUtil::UNKNOWN_DEFAULT;
+  // Get its short (8.3) form if possible.
+  base::string16 app_path;
+  if (!ShortNameFromPath(chrome_exe, &app_path))
+    app_path = chrome_exe.value();
 
   const HKEY root_key = HKEY_CLASSES_ROOT;
   base::string16 key_path;
@@ -1330,11 +1330,14 @@
 
     // Need to normalize path in case it's been munged.
     command_line = base::CommandLine::FromString(value);
-    if (!ShortNameFromPath(command_line.GetProgram(), &short_path))
-      return ShellUtil::UNKNOWN_DEFAULT;
-
-    if (!base::FilePath::CompareEqualIgnoreCase(short_path, short_app_path))
-      return ShellUtil::NOT_DEFAULT;
+    if (ShortNameFromPath(command_line.GetProgram(), &short_path)) {
+      if (!base::FilePath::CompareEqualIgnoreCase(short_path, app_path))
+        return ShellUtil::NOT_DEFAULT;
+    } else {
+      if (!base::FilePath::CompareEqualIgnoreCase(
+              command_line.GetProgram().value(), app_path))
+        return ShellUtil::NOT_DEFAULT;
+    }
   }
 
   return ShellUtil::IS_DEFAULT;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 218f1d4..18fe2c9 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -780,9 +780,7 @@
   # The _run targets exist only for compatibility w/ GYP.
   group("browser_tests_run") {
     testonly = true
-    data_deps = [
-      ":browser_tests",
-    ]
+    data_deps = [ ":browser_tests" ]
   }
 
   test("browser_tests") {
@@ -1333,9 +1331,7 @@
       "//third_party/WebKit/public:blink",
     ]
 
-    data_deps = [
-      "//third_party/mesa:osmesa",
-    ]
+    data_deps = [ "//third_party/mesa:osmesa" ]
 
     if (cld_version == 2) {
       # Language detection is irrelevant to sync, so it can depend on any
diff --git a/chrome/test/data/extensions/ui/browser_action_popup/manifest.json b/chrome/test/data/extensions/ui/browser_action_popup/manifest.json
index 3371986..9669f940 100644
--- a/chrome/test/data/extensions/ui/browser_action_popup/manifest.json
+++ b/chrome/test/data/extensions/ui/browser_action_popup/manifest.json
@@ -5,6 +5,5 @@
   "version": "0.1",
   "browser_action": {
     "default_popup": "popup.html"
-  },
-  "homepage_url": "https://www.google.com/"
+  }
 }
diff --git a/chrome/third_party/mozilla_security_manager/BUILD.gn b/chrome/third_party/mozilla_security_manager/BUILD.gn
new file mode 100644
index 0000000..5aa58cf
--- /dev/null
+++ b/chrome/third_party/mozilla_security_manager/BUILD.gn
@@ -0,0 +1,24 @@
+# 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.
+
+source_set("mozilla_security_manager") {
+  sources = [
+    "nsNSSCertHelper.cpp",
+    "nsNSSCertHelper.h",
+    "nsNSSCertificate.cpp",
+    "nsNSSCertificate.h",
+    "nsUsageArrayHelper.cpp",
+    "nsUsageArrayHelper.h",
+  ]
+
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//chrome/app:generated_resources",
+    "//crypto:platform",
+    "//net",
+    "//third_party/icu",
+    "//ui/base",
+  ]
+}
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index 3d09c61..ee6c0366 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -44,11 +44,8 @@
 #endif
 
 #if defined(ENABLE_EXTENSIONS)
-#include "chrome/common/extensions/chrome_utility_extensions_messages.h"
 #include "chrome/utility/extensions/extensions_handler.h"
 #include "chrome/utility/image_writer/image_writer_handler.h"
-#include "chrome/utility/media_galleries/ipc_data_source.h"
-#include "chrome/utility/media_galleries/media_metadata_parser.h"
 #endif
 
 #if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
@@ -73,17 +70,6 @@
   content::UtilityThread::Get()->ReleaseProcessIfNeeded();
 }
 
-#if defined(ENABLE_EXTENSIONS)
-void FinishParseMediaMetadata(
-    metadata::MediaMetadataParser* /* parser */,
-    const extensions::api::media_galleries::MediaMetadata& metadata,
-    const std::vector<metadata::AttachedImage>& attached_images) {
-  Send(new ChromeUtilityHostMsg_ParseMediaMetadata_Finished(
-      true, *metadata.ToValue(), attached_images));
-  ReleaseProcessIfNeeded();
-}
-#endif
-
 #if !defined(OS_ANDROID)
 void CreateProxyResolverFactory(
     mojo::InterfaceRequest<net::interfaces::ProxyResolverFactory> request) {
@@ -135,7 +121,7 @@
 #endif
 
 #if defined(ENABLE_EXTENSIONS)
-  handlers_.push_back(new extensions::ExtensionsHandler());
+  handlers_.push_back(new extensions::ExtensionsHandler(this));
   handlers_.push_back(new image_writer::ImageWriterHandler());
 #endif
 
@@ -199,12 +185,8 @@
 #if defined(OS_MACOSX)
     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_AnalyzeDmgFileForDownloadProtection,
                         OnAnalyzeDmgFileForDownloadProtection)
-#endif
-#endif
-#if defined(ENABLE_EXTENSIONS)
-    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseMediaMetadata,
-                        OnParseMediaMetadata)
-#endif
+#endif  // defined(OS_MACOSX)
+#endif  // defined(FULL_SAFE_BROWSING)
 #if defined(OS_CHROMEOS)
     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile, OnCreateZipFile)
 #endif
@@ -229,6 +211,11 @@
 #endif
 }
 
+void ChromeContentUtilityClient::AddHandler(
+    scoped_ptr<UtilityMessageHandler> handler) {
+  handlers_.push_back(handler.Pass());
+}
+
 // static
 void ChromeContentUtilityClient::PreSandboxStartup() {
 #if defined(ENABLE_EXTENSIONS)
@@ -415,21 +402,6 @@
       results));
   ReleaseProcessIfNeeded();
 }
-#endif
+#endif  // defined(OS_MACOSX)
 
-#endif
-
-#if defined(ENABLE_EXTENSIONS)
-// TODO(thestig): Try to move this to
-// chrome/utility/extensions/extensions_handler.cc.
-void ChromeContentUtilityClient::OnParseMediaMetadata(
-    const std::string& mime_type, int64 total_size, bool get_attached_images) {
-  // Only one IPCDataSource may be created and added to the list of handlers.
-  metadata::IPCDataSource* source = new metadata::IPCDataSource(total_size);
-  handlers_.push_back(source);
-
-  metadata::MediaMetadataParser* parser = new metadata::MediaMetadataParser(
-      source, mime_type, get_attached_images);
-  parser->Start(base::Bind(&FinishParseMediaMetadata, base::Owned(parser)));
-}
-#endif
+#endif  // defined(FULL_SAFE_BROWSING)
diff --git a/chrome/utility/chrome_content_utility_client.h b/chrome/utility/chrome_content_utility_client.h
index 039791b..1302cd12 100644
--- a/chrome/utility/chrome_content_utility_client.h
+++ b/chrome/utility/chrome_content_utility_client.h
@@ -30,6 +30,8 @@
   bool OnMessageReceived(const IPC::Message& message) override;
   void RegisterMojoServices(content::ServiceRegistry* registry) override;
 
+  void AddHandler(scoped_ptr<UtilityMessageHandler> handler);
+
   static void PreSandboxStartup();
 
   // Shared with extensions::ExtensionsHandler.
@@ -72,13 +74,8 @@
 #if defined(OS_MACOSX)
   void OnAnalyzeDmgFileForDownloadProtection(
       const IPC::PlatformFileForTransit& dmg_file);
-#endif
-#endif
-#if defined(ENABLE_EXTENSIONS)
-  void OnParseMediaMetadata(const std::string& mime_type,
-                            int64 total_size,
-                            bool get_attached_images);
-#endif
+#endif  // defined(OS_MACOSX)
+#endif  // defined(FULL_SAFE_BROWSING)
 
   typedef ScopedVector<UtilityMessageHandler> Handlers;
   Handlers handlers_;
diff --git a/chrome/utility/extensions/extensions_handler.cc b/chrome/utility/extensions/extensions_handler.cc
index 942545e..25586e9b 100644
--- a/chrome/utility/extensions/extensions_handler.cc
+++ b/chrome/utility/extensions/extensions_handler.cc
@@ -12,6 +12,8 @@
 #include "chrome/common/media_galleries/metadata_types.h"
 #include "chrome/utility/chrome_content_utility_client.h"
 #include "chrome/utility/media_galleries/image_metadata_extractor.h"
+#include "chrome/utility/media_galleries/ipc_data_source.h"
+#include "chrome/utility/media_galleries/media_metadata_parser.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/utility/utility_thread.h"
 #include "extensions/common/extension.h"
@@ -51,9 +53,19 @@
   content::UtilityThread::Get()->ReleaseProcessIfNeeded();
 }
 
+void FinishParseMediaMetadata(
+    metadata::MediaMetadataParser* /* parser */,
+    const extensions::api::media_galleries::MediaMetadata& metadata,
+    const std::vector<metadata::AttachedImage>& attached_images) {
+  Send(new ChromeUtilityHostMsg_ParseMediaMetadata_Finished(
+      true, *metadata.ToValue(), attached_images));
+  ReleaseProcessIfNeeded();
+}
+
 }  // namespace
 
-ExtensionsHandler::ExtensionsHandler() {
+ExtensionsHandler::ExtensionsHandler(ChromeContentUtilityClient* utility_client)
+    : utility_client_(utility_client) {
   ExtensionsClient::Set(ChromeExtensionsClient::GetInstance());
 }
 
@@ -73,6 +85,9 @@
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(ExtensionsHandler, message)
     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CheckMediaFile, OnCheckMediaFile)
+    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseMediaMetadata,
+                        OnParseMediaMetadata)
+
 #if defined(OS_WIN)
     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseITunesPrefXml,
                         OnParseITunesPrefXml)
@@ -113,6 +128,17 @@
   ReleaseProcessIfNeeded();
 }
 
+void ExtensionsHandler::OnParseMediaMetadata(
+    const std::string& mime_type, int64 total_size, bool get_attached_images) {
+  // Only one IPCDataSource may be created and added to the list of handlers.
+  scoped_ptr<metadata::IPCDataSource> source(
+      new metadata::IPCDataSource(total_size));
+  metadata::MediaMetadataParser* parser = new metadata::MediaMetadataParser(
+      source.get(), mime_type, get_attached_images);
+  utility_client_->AddHandler(source.Pass());
+  parser->Start(base::Bind(&FinishParseMediaMetadata, base::Owned(parser)));
+}
+
 #if defined(OS_WIN)
 void ExtensionsHandler::OnParseITunesPrefXml(
     const std::string& itunes_xml_data) {
diff --git a/chrome/utility/extensions/extensions_handler.h b/chrome/utility/extensions/extensions_handler.h
index 06f3601..fadf3e81 100644
--- a/chrome/utility/extensions/extensions_handler.h
+++ b/chrome/utility/extensions/extensions_handler.h
@@ -16,6 +16,8 @@
 #error "Extensions must be enabled"
 #endif
 
+class ChromeContentUtilityClient;
+
 namespace metadata {
 class MediaMetadataParser;
 }
@@ -25,7 +27,7 @@
 // Dispatches IPCs for Chrome extensions utility messages.
 class ExtensionsHandler : public UtilityMessageHandler {
  public:
-  ExtensionsHandler();
+  explicit ExtensionsHandler(ChromeContentUtilityClient* utility_client);
   ~ExtensionsHandler() override;
 
   static void PreSandboxStartup();
@@ -38,6 +40,10 @@
   void OnCheckMediaFile(int64 milliseconds_of_decoding,
                         const IPC::PlatformFileForTransit& media_file);
 
+  void OnParseMediaMetadata(const std::string& mime_type,
+                            int64 total_size,
+                            bool get_attached_images);
+
 #if defined(OS_WIN)
   void OnParseITunesPrefXml(const std::string& itunes_xml_data);
 #endif  // defined(OS_WIN)
@@ -65,6 +71,9 @@
 
   UtilityHandler utility_handler_;
 
+  // The client that owns this.
+  ChromeContentUtilityClient* const utility_client_;
+
   DISALLOW_COPY_AND_ASSIGN(ExtensionsHandler);
 };
 
diff --git a/chromecast/media/audio/cast_audio_output_stream.cc b/chromecast/media/audio/cast_audio_output_stream.cc
index 73c935b3..e55f127 100644
--- a/chromecast/media/audio/cast_audio_output_stream.cc
+++ b/chromecast/media/audio/cast_audio_output_stream.cc
@@ -86,7 +86,9 @@
 
     backend_task_runner_.reset(new TaskRunnerImpl());
     MediaPipelineDeviceParams device_params(
-        MediaPipelineDeviceParams::kModeIgnorePts, backend_task_runner_.get());
+        MediaPipelineDeviceParams::kModeIgnorePts,
+        MediaPipelineDeviceParams::kAudioStreamSoundEffects,
+        backend_task_runner_.get());
     backend_ = audio_manager->CreateMediaPipelineBackend(device_params);
     if (backend_)
       decoder_ = InitializeBackend(audio_params_, backend_.get(), this);
diff --git a/chromecast/public/media/media_pipeline_device_params.h b/chromecast/public/media/media_pipeline_device_params.h
index b307dc4..680da27 100644
--- a/chromecast/public/media/media_pipeline_device_params.h
+++ b/chromecast/public/media/media_pipeline_device_params.h
@@ -27,14 +27,36 @@
     kModeIgnorePtsAndVSync = 2,
   };
 
+  enum AudioStreamType {
+    // "Real" audio stream. If this stream underruns, all audio output may pause
+    // until more real stream data is available.
+    kAudioStreamNormal = 0,
+    // Sound-effects audio stream. May be interrupted if a real audio stream
+    // is created with a different sample rate. Underruns on an effects stream
+    // do not affect output of real audio streams.
+    kAudioStreamSoundEffects = 1,
+  };
+
   MediaPipelineDeviceParams(TaskRunner* task_runner_in)
-      : sync_type(kModeSyncPts), task_runner(task_runner_in) {}
+      : sync_type(kModeSyncPts),
+        audio_type(kAudioStreamNormal),
+        task_runner(task_runner_in) {}
 
   MediaPipelineDeviceParams(MediaSyncType sync_type_in,
                             TaskRunner* task_runner_in)
-      : sync_type(sync_type_in), task_runner(task_runner_in) {}
+      : sync_type(sync_type_in),
+        audio_type(kAudioStreamNormal),
+        task_runner(task_runner_in) {}
+
+  MediaPipelineDeviceParams(MediaSyncType sync_type_in,
+                            AudioStreamType audio_type_in,
+                            TaskRunner* task_runner_in)
+      : sync_type(sync_type_in),
+        audio_type(audio_type_in),
+        task_runner(task_runner_in) {}
 
   const MediaSyncType sync_type;
+  const AudioStreamType audio_type;
 
   // task_runner allows backend implementations to post tasks to the media
   // thread.  Since all calls from cast_shell into the backend are made on
diff --git a/cloud_print/service/win/BUILD.gn b/cloud_print/service/win/BUILD.gn
index 211ccc33..2c050b0b 100644
--- a/cloud_print/service/win/BUILD.gn
+++ b/cloud_print/service/win/BUILD.gn
@@ -44,24 +44,7 @@
   output = "$target_gen_dir/cloud_print_service_exe_version.rc"
 }
 
-executable("cloud_print_service_config") {
-  sources = [
-    "cloud_print_service_config.cc",
-  ]
-
-  configs -= [ "//build/config/win:console" ]
-  configs += [ "//build/config/win:windowed" ]
-
-  deps = [
-    ":config_version",
-    ":exe_manifest",
-    "//cloud_print/common:install_utils",
-    "//cloud_print/service:resources",
-    "//cloud_print/service:lib",
-  ]
-
-  libs = [ "secur32.lib" ]
-
+config("cloud_print_service_config_warnings") {
   # TODO: Remove once cloud_print_service_config.cc no longer depends on
   # atlapp.h, http://crbug.com/5027
   if (is_clang) {
@@ -81,6 +64,28 @@
   }
 }
 
+executable("cloud_print_service_config") {
+  sources = [
+    "cloud_print_service_config.cc",
+  ]
+
+  configs -= [ "//build/config/win:console" ]
+  configs += [
+    "//build/config/win:windowed",
+    ":cloud_print_service_config_warnings",
+  ]
+
+  deps = [
+    ":config_version",
+    ":exe_manifest",
+    "//cloud_print/common:install_utils",
+    "//cloud_print/service:resources",
+    "//cloud_print/service:lib",
+  ]
+
+  libs = [ "secur32.lib" ]
+}
+
 process_version("config_version") {
   template_file = chrome_version_rc_template
   sources = [
diff --git a/cloud_print/virtual_driver/win/port_monitor/BUILD.gn b/cloud_print/virtual_driver/win/port_monitor/BUILD.gn
index a9e5b359..f6e727f 100644
--- a/cloud_print/virtual_driver/win/port_monitor/BUILD.gn
+++ b/cloud_print/virtual_driver/win/port_monitor/BUILD.gn
@@ -14,8 +14,6 @@
   arch_suffix = ""
 }
 
-print("port_monitor $current_toolchain")
-
 shared_library("port_monitor") {
   output_name = "gcp_portmon$arch_suffix"
 
diff --git a/components/BUILD.gn b/components/BUILD.gn
index f1e32cd..03c729c 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -60,6 +60,7 @@
       "//components/compression",
       "//components/content_settings/core/browser",
       "//components/content_settings/core/common",
+      "//components/cookie_config",
       "//components/crash/content/app",
       "//components/crash/content/browser",
       "//components/crx_file",
diff --git a/components/autofill/core/browser/suggestion.cc b/components/autofill/core/browser/suggestion.cc
index c5b150e..22d4ac7 100644
--- a/components/autofill/core/browser/suggestion.cc
+++ b/components/autofill/core/browser/suggestion.cc
@@ -5,8 +5,6 @@
 #include "components/autofill/core/browser/suggestion.h"
 
 #include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/autofill_profile.h"
-#include "components/autofill/core/browser/credit_card.h"
 
 namespace autofill {
 
diff --git a/components/autofill/core/browser/suggestion.h b/components/autofill/core/browser/suggestion.h
index ebf16073..930ab23 100644
--- a/components/autofill/core/browser/suggestion.h
+++ b/components/autofill/core/browser/suggestion.h
@@ -7,16 +7,11 @@
 
 #include <string>
 
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 
 namespace autofill {
 
-class AutofillProfile;
-class CreditCard;
-
 struct Suggestion {
- public:
   enum MatchMode {
     PREFIX_MATCH,    // for prefix matched suggestions;
     SUBSTRING_MATCH  // for substring matched suggestions;
diff --git a/components/component_updater/configurator_impl.cc b/components/component_updater/configurator_impl.cc
index cc6d7f0..fb8f1db 100644
--- a/components/component_updater/configurator_impl.cc
+++ b/components/component_updater/configurator_impl.cc
@@ -192,4 +192,8 @@
   return background_downloads_enabled_;
 }
 
+void ConfiguratorImpl::set_enable_alt_source_url(bool enable_alt_source_url) {
+  fallback_to_alt_source_url_enabled_ = enable_alt_source_url;
+}
+
 }  // namespace component_updater
diff --git a/components/component_updater/configurator_impl.h b/components/component_updater/configurator_impl.h
index df58473..b2e75a9 100644
--- a/components/component_updater/configurator_impl.h
+++ b/components/component_updater/configurator_impl.h
@@ -77,6 +77,11 @@
   // non on-demand components.
   bool UseBackgroundDownloader() const;
 
+  // Setting this to false means that we'll only use secure transport (eg https)
+  // for update/ping urls. This is already false by default everywhere but older
+  // versions of Windows XP.
+  void set_enable_alt_source_url(bool enable_alt_source_url);
+
  private:
   net::URLRequestContextGetter* url_request_getter_;
   std::string extra_info_;
diff --git a/components/components.gyp b/components/components.gyp
index 85ac077..39e829f7 100644
--- a/components/components.gyp
+++ b/components/components.gyp
@@ -21,6 +21,7 @@
     'component_updater.gypi',
     'compression.gypi',
     'content_settings.gypi',
+    'cookie_config.gypi',
     'crash.gypi',
     'cronet.gypi',
     'crx_file.gypi',
diff --git a/components/cookie_config.gypi b/components/cookie_config.gypi
new file mode 100644
index 0000000..4c3e8f7
--- /dev/null
+++ b/components/cookie_config.gypi
@@ -0,0 +1,26 @@
+# 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.
+
+{
+  'targets': [
+    {
+      # GN version: //components/cookie_config
+      'target_name': 'cookie_config',
+      'type': 'static_library',
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../net/net.gyp:net',
+        'os_crypt',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'cookie_config/cookie_store_util.cc',
+        'cookie_config/cookie_store_util.h',
+      ],
+    },
+  ],
+}
+
diff --git a/components/cookie_config/BUILD.gn b/components/cookie_config/BUILD.gn
new file mode 100644
index 0000000..fc3b632
--- /dev/null
+++ b/components/cookie_config/BUILD.gn
@@ -0,0 +1,17 @@
+# 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.
+
+# GYP version: components/cookie_config.gypi:cookie_config
+source_set("cookie_config") {
+  sources = [
+    "cookie_store_util.cc",
+    "cookie_store_util.h",
+  ]
+
+  deps = [
+    "//base",
+    "//components/os_crypt",
+    "//net",
+  ]
+}
diff --git a/components/cookie_config/DEPS b/components/cookie_config/DEPS
new file mode 100644
index 0000000..091c0c8
--- /dev/null
+++ b/components/cookie_config/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+components/os_crypt",
+  "+net/extras/sqlite",
+]
diff --git a/components/cookie_config/OWNERS b/components/cookie_config/OWNERS
new file mode 100644
index 0000000..6fe35f0
--- /dev/null
+++ b/components/cookie_config/OWNERS
@@ -0,0 +1,2 @@
+blundell@chromium.org
+rdsmith@chromium.org
diff --git a/chrome/browser/net/cookie_store_util.cc b/components/cookie_config/cookie_store_util.cc
similarity index 85%
rename from chrome/browser/net/cookie_store_util.cc
rename to components/cookie_config/cookie_store_util.cc
index d3882ef..b900ac6 100644
--- a/chrome/browser/net/cookie_store_util.cc
+++ b/components/cookie_config/cookie_store_util.cc
@@ -2,18 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/net/cookie_store_util.h"
+#include "components/cookie_config/cookie_store_util.h"
 
 #include "base/lazy_instance.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_switches.h"
 #include "components/os_crypt/os_crypt.h"
-#include "content/public/common/content_constants.h"
-#include "extensions/common/constants.h"
 #include "net/extras/sqlite/cookie_crypto_delegate.h"
 
-namespace chrome_browser_net {
+namespace cookie_config {
 
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
 namespace {
@@ -67,10 +62,10 @@
 net::CookieCryptoDelegate* GetCookieCryptoDelegate() {
   return g_cookie_crypto_delegate.Pointer();
 }
-#else  // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+#else   // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
 net::CookieCryptoDelegate* GetCookieCryptoDelegate() {
   return NULL;
 }
 #endif  // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
 
-}  // namespace chrome_browser_net
+}  // namespace cookie_config
diff --git a/components/cookie_config/cookie_store_util.h b/components/cookie_config/cookie_store_util.h
new file mode 100644
index 0000000..893e6a0
--- /dev/null
+++ b/components/cookie_config/cookie_store_util.h
@@ -0,0 +1,21 @@
+// 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 COMPONENTS_COOKIE_CONFIG_COOKIE_STORE_UTIL_H_
+#define COMPONENTS_COOKIE_CONFIG_COOKIE_STORE_UTIL_H_
+
+namespace net {
+class CookieCryptoDelegate;
+}  // namespace net
+
+namespace cookie_config {
+
+// Factory method for returning a CookieCryptoDelegate if one is appropriate for
+// this platform. The object returned is a LazyInstance. Ownership is not
+// transferred.
+net::CookieCryptoDelegate* GetCookieCryptoDelegate();
+
+}  // namespace cookie_config
+
+#endif  // COMPONENTS_COOKIE_CONFIG_COOKIE_STORE_UTIL_H_
diff --git a/components/html_viewer/ax_provider_apptest.cc b/components/html_viewer/ax_provider_apptest.cc
index cda4538b..ac703bc 100644
--- a/components/html_viewer/ax_provider_apptest.cc
+++ b/components/html_viewer/ax_provider_apptest.cc
@@ -7,9 +7,10 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/test_timeouts.h"
-#include "components/mus/public/cpp/tests/view_manager_test_base.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
+#include "base/time/time.h"
+#include "components/mus/public/cpp/tests/window_server_test_base.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/web_view/public/interfaces/frame.mojom.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/application/public/cpp/application_test_base.h"
@@ -67,7 +68,7 @@
 
 }  // namespace
 
-using AXProviderTest = mus::ViewManagerTestBase;
+using AXProviderTest = mus::WindowServerTestBase;
 
 TEST_F(AXProviderTest, HelloWorld) {
   // Start a test server for net/data/test.html access.
@@ -84,11 +85,11 @@
   scoped_ptr<ApplicationConnection> connection =
       application_impl()->ConnectToApplication(request.Pass());
 
-  // Embed the html_viewer in a View.
+  // Embed the html_viewer in a Window.
   ViewTreeClientPtr tree_client;
   connection->ConnectToService(&tree_client);
-  mus::View* embed_view = window_manager()->CreateView();
-  embed_view->Embed(tree_client.Pass());
+  mus::Window* embed_window = window_manager()->CreateWindow();
+  embed_window->Embed(tree_client.Pass());
 
   TestFrame frame;
   web_view::mojom::FramePtr frame_ptr;
@@ -97,14 +98,15 @@
 
   mojo::Array<web_view::mojom::FrameDataPtr> array(1u);
   array[0] = web_view::mojom::FrameData::New().Pass();
-  array[0]->frame_id = embed_view->id();
+  array[0]->frame_id = embed_window->id();
   array[0]->parent_id = 0u;
 
   web_view::mojom::FrameClientPtr frame_client;
   connection->ConnectToService(&frame_client);
-  frame_client->OnConnect(frame_ptr.Pass(), 1u, embed_view->id(),
-                          web_view::mojom::VIEW_CONNECT_TYPE_USE_NEW,
-                          array.Pass(), base::Closure());
+  frame_client->OnConnect(
+      frame_ptr.Pass(), 1u, embed_window->id(),
+      web_view::mojom::VIEW_CONNECT_TYPE_USE_NEW, array.Pass(),
+      base::TimeTicks::Now().ToInternalValue(), base::Closure());
 
   // Connect to the AxProvider of the HTML document and get the AxTree.
   AxProviderPtr ax_provider;
diff --git a/components/html_viewer/document_resource_waiter.cc b/components/html_viewer/document_resource_waiter.cc
index fdc96ac..bc6731d73 100644
--- a/components/html_viewer/document_resource_waiter.cc
+++ b/components/html_viewer/document_resource_waiter.cc
@@ -7,7 +7,7 @@
 #include "components/html_viewer/global_state.h"
 #include "components/html_viewer/html_document.h"
 #include "components/html_viewer/html_frame_tree_manager.h"
-#include "components/mus/public/cpp/view.h"
+#include "components/mus/public/cpp/window.h"
 
 using web_view::mojom::ViewConnectType;
 
@@ -21,7 +21,7 @@
       response_(response.Pass()),
       root_(nullptr),
       change_id_(0u),
-      view_id_(0u),
+      window_id_(0u),
       view_connect_type_(web_view::mojom::VIEW_CONNECT_TYPE_USE_NEW),
       frame_client_binding_(this),
       is_ready_(false),
@@ -40,7 +40,7 @@
     web_view::mojom::FramePtr* frame,
     mojo::Array<web_view::mojom::FrameDataPtr>* frame_data,
     uint32_t* change_id,
-    uint32_t* view_id,
+    uint32_t* window_id,
     ViewConnectType* view_connect_type,
     OnConnectCallback* on_connect_callback) {
   DCHECK(is_ready_);
@@ -48,7 +48,7 @@
   *frame = frame_.Pass();
   *frame_data = frame_data_.Pass();
   *change_id = change_id_;
-  *view_id = view_id_;
+  *window_id = window_id_;
   *view_connect_type = view_connect_type_;
   *on_connect_callback = on_connect_callback_;
 }
@@ -57,7 +57,7 @@
   return response_.Pass();
 }
 
-void DocumentResourceWaiter::SetRoot(mus::View* root) {
+void DocumentResourceWaiter::SetRoot(mus::Window* root) {
   DCHECK(!root_);
   root_ = root;
   root_->AddObserver(this);
@@ -123,16 +123,19 @@
 void DocumentResourceWaiter::OnConnect(
     web_view::mojom::FramePtr frame,
     uint32_t change_id,
-    uint32_t view_id,
+    uint32_t window_id,
     ViewConnectType view_connect_type,
     mojo::Array<web_view::mojom::FrameDataPtr> frame_data,
+    int64_t navigation_start_time_ticks,
     const OnConnectCallback& callback) {
   DCHECK(frame_data_.is_null());
   change_id_ = change_id;
-  view_id_ = view_id;
+  window_id_ = window_id;
   view_connect_type_ = view_connect_type;
   frame_ = frame.Pass();
   frame_data_ = frame_data.Pass();
+  navigation_start_time_ =
+      base::TimeTicks::FromInternalValue(navigation_start_time_ticks);
   on_connect_callback_ = callback;
   CHECK(frame_data_.size() > 0u);
   frame_client_request_ = frame_client_binding_.Unbind();
@@ -214,14 +217,14 @@
   NOTREACHED();
 }
 
-void DocumentResourceWaiter::OnViewViewportMetricsChanged(
-    mus::View* view,
+void DocumentResourceWaiter::OnWindowViewportMetricsChanged(
+    mus::Window* window,
     const mojo::ViewportMetrics& old_metrics,
     const mojo::ViewportMetrics& new_metrics) {
   UpdateIsReady();
 }
 
-void DocumentResourceWaiter::OnViewDestroyed(mus::View* view) {
+void DocumentResourceWaiter::OnWindowDestroyed(mus::Window* window) {
   root_->RemoveObserver(this);
   root_ = nullptr;
 }
diff --git a/components/html_viewer/document_resource_waiter.h b/components/html_viewer/document_resource_waiter.h
index 7784548..be22006 100644
--- a/components/html_viewer/document_resource_waiter.h
+++ b/components/html_viewer/document_resource_waiter.h
@@ -6,16 +6,13 @@
 #define COMPONENTS_HTML_VIEWER_DOCUMENT_RESOURCE_WAITER_H_
 
 #include "base/basictypes.h"
+#include "base/time/time.h"
 #include "components/html_viewer/html_frame_tree_manager_observer.h"
-#include "components/mus/public/cpp/view_observer.h"
+#include "components/mus/public/cpp/window_observer.h"
 #include "components/web_view/public/interfaces/frame.mojom.h"
 #include "mojo/services/network/public/interfaces/url_loader.mojom.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
 
-namespace mojo {
-class View;
-}
-
 namespace html_viewer {
 
 class HTMLDocument;
@@ -27,7 +24,7 @@
 // assumed HTMLDocument will call back for the FrameClient and FrameData.
 class DocumentResourceWaiter : public web_view::mojom::FrameClient,
                                public HTMLFrameTreeManagerObserver,
-                               public mus::ViewObserver {
+                               public mus::WindowObserver {
  public:
   DocumentResourceWaiter(GlobalState* global_state,
                          mojo::URLResponsePtr response,
@@ -39,7 +36,7 @@
                    frame_client_request,
                web_view::mojom::FramePtr* frame,
                mojo::Array<web_view::mojom::FrameDataPtr>* frame_data,
-               uint32_t* view_id,
+               uint32_t* window_id,
                uint32_t* change_id,
                web_view::mojom::ViewConnectType* view_connect_type,
                OnConnectCallback* on_connect_callback);
@@ -51,8 +48,12 @@
   // See class description.
   bool is_ready() const { return is_ready_; }
 
-  void SetRoot(mus::View* root);
-  mus::View* root() { return root_; }
+  base::TimeTicks navigation_start_time() const {
+    return navigation_start_time_;
+  }
+
+  void SetRoot(mus::Window* root);
+  mus::Window* root() { return root_; }
 
   void Bind(mojo::InterfaceRequest<web_view::mojom::FrameClient> request);
 
@@ -63,9 +64,10 @@
   // web_view::mojom::FrameClient:
   void OnConnect(web_view::mojom::FramePtr frame,
                  uint32_t change_id,
-                 uint32_t view_id,
+                 uint32_t window_id,
                  web_view::mojom::ViewConnectType view_connect_type,
                  mojo::Array<web_view::mojom::FrameDataPtr> frame_data,
+                 int64_t navigation_start_time_ticks,
                  const OnConnectCallback& callback) override;
   void OnFrameAdded(uint32_t change_id,
                     web_view::mojom::FrameDataPtr frame_data) override;
@@ -92,12 +94,12 @@
                             bool reset) override;
   void StopHighlightingFindResults() override;
 
-  // ViewObserver:
-  void OnViewViewportMetricsChanged(
-      mus::View* view,
+  // WindowObserver:
+  void OnWindowViewportMetricsChanged(
+      mus::Window* window,
       const mojo::ViewportMetrics& old_metrics,
       const mojo::ViewportMetrics& new_metrics) override;
-  void OnViewDestroyed(mus::View* view) override;
+  void OnWindowDestroyed(mus::Window* window) override;
 
   // HTMLFrameTreeManagerObserver:
   void OnHTMLFrameTreeManagerChangeIdAdvanced() override;
@@ -106,11 +108,12 @@
   GlobalState* global_state_;
   HTMLDocument* document_;
   mojo::URLResponsePtr response_;
-  mus::View* root_;
+  mus::Window* root_;
   web_view::mojom::FramePtr frame_;
   mojo::Array<web_view::mojom::FrameDataPtr> frame_data_;
   uint32_t change_id_;
-  uint32_t view_id_;
+  uint32_t window_id_;
+  base::TimeTicks navigation_start_time_;
   web_view::mojom::ViewConnectType view_connect_type_;
   OnConnectCallback on_connect_callback_;
 
diff --git a/components/html_viewer/global_state.cc b/components/html_viewer/global_state.cc
index e9c295f..fa3eb705 100644
--- a/components/html_viewer/global_state.cc
+++ b/components/html_viewer/global_state.cc
@@ -20,6 +20,7 @@
 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
+#include "ui/gfx/display.h"
 #include "ui/mojo/init/ui_init.h"
 #include "v8/include/v8.h"
 
@@ -56,16 +57,26 @@
   return paths;
 }
 
+// TODO(sky): convert to using DisplayService.
+std::vector<gfx::Display> DisplaysFromSizeAndScale(
+    const gfx::Size& screen_size_in_pixels,
+    float device_pixel_ratio) {
+  std::vector<gfx::Display> displays(1);
+  displays[0].set_id(2000);
+  displays[0].SetScaleAndBounds(device_pixel_ratio,
+                                gfx::Rect(screen_size_in_pixels));
+  return displays;
+}
+
 }  // namespace
 
 GlobalState::GlobalState(mojo::ApplicationImpl* app)
     : app_(app),
-      resource_loader_(app->shell(), GetResourcePaths()),
+      resource_loader_(app, GetResourcePaths()),
       did_init_(false),
       device_pixel_ratio_(1.f),
       discardable_memory_allocator_(kDesiredMaxMemory),
-      compositor_thread_("compositor thread") {
-}
+      compositor_thread_("compositor thread") {}
 
 GlobalState::~GlobalState() {
   if (blink_platform_) {
@@ -105,8 +116,8 @@
   SkFontConfigInterface::SetGlobal(font_loader_.get());
 #endif
 
-  ui_init_.reset(
-      new ui::mojo::UIInit(screen_size_in_pixels, device_pixel_ratio));
+  ui_init_.reset(new ui::mojo::UIInit(
+      DisplaysFromSizeAndScale(screen_size_in_pixels_, device_pixel_ratio_)));
   base::DiscardableMemoryAllocator::SetInstance(&discardable_memory_allocator_);
 
   mojo::URLRequestPtr request(mojo::URLRequest::New());
diff --git a/components/html_viewer/html_document.cc b/components/html_viewer/html_document.cc
index fd6df51..adf7cbf6 100644
--- a/components/html_viewer/html_document.cc
+++ b/components/html_viewer/html_document.cc
@@ -10,6 +10,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
 #include "components/html_viewer/blink_url_request_type_converters.h"
 #include "components/html_viewer/devtools_agent_impl.h"
 #include "components/html_viewer/document_resource_waiter.h"
@@ -18,8 +19,8 @@
 #include "components/html_viewer/html_frame_tree_manager.h"
 #include "components/html_viewer/test_html_viewer_impl.h"
 #include "components/html_viewer/web_url_loader_impl.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/mus/vm/ids.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/application/public/cpp/connect.h"
@@ -31,7 +32,7 @@
 #include "ui/gfx/geometry/size.h"
 
 using mojo::AxProvider;
-using mus::View;
+using mus::Window;
 
 namespace html_viewer {
 namespace {
@@ -45,28 +46,28 @@
 
 }  // namespace
 
-// A ViewTreeDelegate implementation that delegates to a (swappable) delegate.
+// A WindowTreeDelegate implementation that delegates to a (swappable) delegate.
 // This is used when one HTMLDocument takes over for another delegate
 // (OnSwap()).
-class ViewTreeDelegateImpl : public mus::ViewTreeDelegate {
+class WindowTreeDelegateImpl : public mus::WindowTreeDelegate {
  public:
-  explicit ViewTreeDelegateImpl(mus::ViewTreeDelegate* delegate)
+  explicit WindowTreeDelegateImpl(mus::WindowTreeDelegate* delegate)
       : delegate_(delegate) {}
-  ~ViewTreeDelegateImpl() override {}
+  ~WindowTreeDelegateImpl() override {}
 
-  void set_delegate(mus::ViewTreeDelegate* delegate) { delegate_ = delegate; }
+  void set_delegate(mus::WindowTreeDelegate* delegate) { delegate_ = delegate; }
 
  private:
-  // ViewTreeDelegate:
-  void OnEmbed(mus::View* root) override { delegate_->OnEmbed(root); }
+  // WindowTreeDelegate:
+  void OnEmbed(mus::Window* root) override { delegate_->OnEmbed(root); }
   void OnUnembed() override { delegate_->OnUnembed(); }
-  void OnConnectionLost(mus::ViewTreeConnection* connection) override {
+  void OnConnectionLost(mus::WindowTreeConnection* connection) override {
     delegate_->OnConnectionLost(connection);
   }
 
-  mus::ViewTreeDelegate* delegate_;
+  mus::WindowTreeDelegate* delegate_;
 
-  DISALLOW_COPY_AND_ASSIGN(ViewTreeDelegateImpl);
+  DISALLOW_COPY_AND_ASSIGN(WindowTreeDelegateImpl);
 };
 
 HTMLDocument::BeforeLoadCache::BeforeLoadCache() {}
@@ -77,17 +78,17 @@
 }
 
 HTMLDocument::TransferableState::TransferableState()
-    : owns_view_tree_connection(false), root(nullptr) {}
+    : owns_window_tree_connection(false), root(nullptr) {}
 
 HTMLDocument::TransferableState::~TransferableState() {}
 
 void HTMLDocument::TransferableState::Move(TransferableState* other) {
-  owns_view_tree_connection = other->owns_view_tree_connection;
+  owns_window_tree_connection = other->owns_window_tree_connection;
   root = other->root;
-  view_tree_delegate_impl = other->view_tree_delegate_impl.Pass();
+  window_tree_delegate_impl = other->window_tree_delegate_impl.Pass();
 
   other->root = nullptr;
-  other->owns_view_tree_connection = false;
+  other->owns_window_tree_connection = false;
 }
 
 HTMLDocument::HTMLDocument(mojo::ApplicationImpl* html_document_app,
@@ -117,7 +118,7 @@
 
 void HTMLDocument::Destroy() {
   if (resource_waiter_) {
-    mus::View* root = resource_waiter_->root();
+    mus::Window* root = resource_waiter_->root();
     if (root) {
       resource_waiter_.reset();
       delete root->connection();
@@ -130,7 +131,7 @@
     frame_->Close();
   } else if (transferable_state_.root) {
     // This triggers deleting us.
-    if (transferable_state_.owns_view_tree_connection)
+    if (transferable_state_.owns_window_tree_connection)
       delete transferable_state_.root->connection();
     else
       delete this;
@@ -149,7 +150,7 @@
   DCHECK(resource_waiter_ && resource_waiter_->is_ready());
 
   // Note: |view| is null if we're taking over for an existing frame.
-  mus::View* view = resource_waiter_->root();
+  mus::Window* view = resource_waiter_->root();
   if (view) {
     global_state_->InitIfNecessary(
         view->viewport_metrics().size_in_pixels.To<gfx::Size>(),
@@ -160,6 +161,8 @@
   extra_data->synthetic_response =
       resource_waiter_->ReleaseURLResponse().Pass();
 
+  base::TimeTicks navigation_start_time =
+      resource_waiter_->navigation_start_time();
   frame_ = HTMLFrameTreeManager::CreateFrameAndAttachToTree(
       global_state_, view, resource_waiter_.Pass(), this);
 
@@ -185,7 +188,7 @@
   web_request.setURL(url);
   web_request.setExtraData(extra_data.release());
 
-  frame_->LoadRequest(web_request);
+  frame_->LoadRequest(web_request, navigation_start_time);
 }
 
 HTMLDocument::BeforeLoadCache* HTMLDocument::GetBeforeLoadCache() {
@@ -195,12 +198,12 @@
   return before_load_cache_.get();
 }
 
-void HTMLDocument::OnEmbed(View* root) {
+void HTMLDocument::OnEmbed(Window* root) {
   transferable_state_.root = root;
   resource_waiter_->SetRoot(root);
 }
 
-void HTMLDocument::OnConnectionLost(mus::ViewTreeConnection* connection) {
+void HTMLDocument::OnConnectionLost(mus::WindowTreeConnection* connection) {
   delete this;
 }
 
@@ -238,27 +241,27 @@
 
 void HTMLDocument::OnSwap(HTMLFrame* frame, HTMLFrameDelegate* old_delegate) {
   DCHECK(frame->IsLocal());
-  DCHECK(frame->view());
+  DCHECK(frame->window());
   DCHECK(!frame_);
   DCHECK(!transferable_state_.root);
   if (!old_delegate) {
     // We're taking over a child of a local root that isn't associated with a
     // delegate. In this case the frame's view is not the root of the
-    // ViewTreeConnection.
-    transferable_state_.owns_view_tree_connection = false;
-    transferable_state_.root = frame->view();
+    // WindowTreeConnection.
+    transferable_state_.owns_window_tree_connection = false;
+    transferable_state_.root = frame->window();
   } else {
     HTMLDocument* old_document = static_cast<HTMLDocument*>(old_delegate);
     transferable_state_.Move(&old_document->transferable_state_);
-    if (transferable_state_.view_tree_delegate_impl)
-      transferable_state_.view_tree_delegate_impl->set_delegate(this);
+    if (transferable_state_.window_tree_delegate_impl)
+      transferable_state_.window_tree_delegate_impl->set_delegate(this);
     old_document->frame_ = nullptr;
     old_document->Destroy();
   }
 }
 
 void HTMLDocument::OnFrameDestroyed() {
-  if (!transferable_state_.owns_view_tree_connection)
+  if (!transferable_state_.owns_window_tree_connection)
     delete this;
 }
 
@@ -312,13 +315,13 @@
 void HTMLDocument::Create(
     mojo::ApplicationConnection* connection,
     mojo::InterfaceRequest<mojo::ViewTreeClient> request) {
-  DCHECK(!transferable_state_.view_tree_delegate_impl);
-  transferable_state_.view_tree_delegate_impl.reset(
-      new ViewTreeDelegateImpl(this));
-  transferable_state_.owns_view_tree_connection = true;
-  mus::ViewTreeConnection::Create(
-      transferable_state_.view_tree_delegate_impl.get(), request.Pass(),
-      mus::ViewTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
+  DCHECK(!transferable_state_.window_tree_delegate_impl);
+  transferable_state_.window_tree_delegate_impl.reset(
+      new WindowTreeDelegateImpl(this));
+  transferable_state_.owns_window_tree_connection = true;
+  mus::WindowTreeConnection::Create(
+      transferable_state_.window_tree_delegate_impl.get(), request.Pass(),
+      mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
 }
 
 }  // namespace html_viewer
diff --git a/components/html_viewer/html_document.h b/components/html_viewer/html_document.h
index 501d688..2b82384e 100644
--- a/components/html_viewer/html_document.h
+++ b/components/html_viewer/html_document.h
@@ -15,7 +15,7 @@
 #include "components/html_viewer/ax_provider_impl.h"
 #include "components/html_viewer/html_frame_delegate.h"
 #include "components/html_viewer/public/interfaces/test_html_viewer.mojom.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
 #include "components/web_view/public/interfaces/frame.mojom.h"
 #include "mojo/application/public/cpp/app_lifetime_helper.h"
 #include "mojo/application/public/cpp/interface_factory.h"
@@ -28,8 +28,8 @@
 }
 
 namespace mus {
-class View;
-class ViewTreeConnection;
+class Window;
+class WindowTreeConnection;
 }
 
 namespace html_viewer {
@@ -40,7 +40,7 @@
 class HTMLFactory;
 class HTMLFrame;
 class TestHTMLViewerImpl;
-class ViewTreeDelegateImpl;
+class WindowTreeDelegateImpl;
 class WebLayerTreeViewImpl;
 
 // A view for a single HTML document.
@@ -49,7 +49,7 @@
 // . When the View the HTMLDocument is embedded in is destroyed.
 // . Explicitly by way of Destroy().
 class HTMLDocument
-    : public mus::ViewTreeDelegate,
+    : public mus::WindowTreeDelegate,
       public HTMLFrameDelegate,
       public mojo::InterfaceFactory<mojo::AxProvider>,
       public mojo::InterfaceFactory<web_view::mojom::FrameClient>,
@@ -95,9 +95,9 @@
     // Takes the state from |other|.
     void Move(TransferableState* other);
 
-    bool owns_view_tree_connection;
-    mus::View* root;
-    scoped_ptr<ViewTreeDelegateImpl> view_tree_delegate_impl;
+    bool owns_window_tree_connection;
+    mus::Window* root;
+    scoped_ptr<WindowTreeDelegateImpl> window_tree_delegate_impl;
   };
 
   ~HTMLDocument() override;
@@ -106,9 +106,9 @@
 
   BeforeLoadCache* GetBeforeLoadCache();
 
-  // ViewTreeDelegate:
-  void OnEmbed(mus::View* root) override;
-  void OnConnectionLost(mus::ViewTreeConnection* connection) override;
+  // WindowTreeDelegate:
+  void OnEmbed(mus::Window* root) override;
+  void OnConnectionLost(mus::WindowTreeConnection* connection) override;
 
   // HTMLFrameDelegate:
   mojo::ApplicationImpl* GetApp() override;
diff --git a/components/html_viewer/html_frame.cc b/components/html_viewer/html_frame.cc
index 980534e7..c1b084d8 100644
--- a/components/html_viewer/html_frame.cc
+++ b/components/html_viewer/html_frame.cc
@@ -34,9 +34,9 @@
 #include "components/html_viewer/web_layer_tree_view_impl.h"
 #include "components/html_viewer/web_storage_namespace_impl.h"
 #include "components/html_viewer/web_url_loader_impl.h"
-#include "components/mus/public/cpp/scoped_view_ptr.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
+#include "components/mus/public/cpp/scoped_window_ptr.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/mus/vm/ids.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/application/public/cpp/connect.h"
@@ -74,7 +74,6 @@
 using mojo::Rect;
 using mojo::ServiceProviderPtr;
 using mojo::URLResponsePtr;
-using mus::View;
 using web_view::mojom::HTMLMessageEvent;
 using web_view::mojom::HTMLMessageEventPtr;
 
@@ -121,7 +120,7 @@
 HTMLFrame::HTMLFrame(CreateParams* params)
     : frame_tree_manager_(params->manager),
       parent_(params->parent),
-      view_(nullptr),
+      window_(nullptr),
       id_(params->id),
       web_frame_(nullptr),
       delegate_(params->delegate),
@@ -130,8 +129,8 @@
   if (parent_)
     parent_->children_.push_back(this);
 
-  if (params->view && params->view->id() == id_)
-    SetView(params->view);
+  if (params->window && params->window->id() == id_)
+    SetWindow(params->window);
 
   SetReplicatedFrameStateFromClientProperties(params->properties, &state_);
 
@@ -151,14 +150,14 @@
 
     // The resize and setDeviceScaleFactor() needs to be after setting the main
     // frame.
-    const gfx::Size size_in_pixels(params->view->bounds().width,
-                                   params->view->bounds().height);
+    const gfx::Size size_in_pixels(params->window->bounds().width,
+                                   params->window->bounds().height);
     const gfx::Size size_in_dips = gfx::ConvertSizeToDIP(
-        params->view->viewport_metrics().device_pixel_ratio, size_in_pixels);
+        params->window->viewport_metrics().device_pixel_ratio, size_in_pixels);
     web_view()->resize(size_in_dips);
     web_frame_ = local_web_frame;
     web_view()->setDeviceScaleFactor(global_state()->device_pixel_ratio());
-    if (id_ != params->view->id()) {
+    if (id_ != params->window->id()) {
       blink::WebRemoteFrame* remote_web_frame =
           blink::WebRemoteFrame::create(state_.tree_scope, this);
       local_web_frame->swap(remote_web_frame);
@@ -182,8 +181,8 @@
       startup_performance_data_collector_ =
           StatsCollectionController::Install(web_frame_, GetApp());
     }
-  } else if (!params->is_local_create_child && params->view &&
-             id_ == params->view->id()) {
+  } else if (!params->is_local_create_child && params->window &&
+             id_ == params->window->id()) {
     // Frame represents the local frame, and it isn't the root of the tree.
     HTMLFrame* previous_sibling = GetPreviousSibling(this);
     blink::WebFrame* previous_web_frame =
@@ -272,13 +271,15 @@
   return false;
 }
 
-void HTMLFrame::LoadRequest(const blink::WebURLRequest& request) {
+void HTMLFrame::LoadRequest(const blink::WebURLRequest& request,
+                            base::TimeTicks navigation_start_time) {
   DCHECK(IsLocal());
 
   DVLOG(2) << "HTMLFrame::LoadRequest this=" << this << " id=" << id_
            << " URL=" << GURL(request.url());
 
   pending_navigation_ = false;
+  navigation_start_time_ = navigation_start_time;
   web_frame_->toWebLocalFrame()->loadRequest(request);
 }
 
@@ -299,9 +300,9 @@
   if (delegate_)
     delegate_->OnFrameDestroyed();
 
-  if (view_) {
-    view_->RemoveObserver(this);
-    mus::ScopedViewPtr::DeleteViewOrViewManager(view_);
+  if (window_) {
+    window_->RemoveObserver(this);
+    mus::ScopedWindowPtr::DeleteWindowOrWindowManager(window_);
   }
 }
 
@@ -322,10 +323,10 @@
     blink::WebSandboxFlags sandbox_flags) {
   DCHECK(IsLocal());  // Can't create children of remote frames.
   DCHECK_EQ(parent, web_frame_);
-  DCHECK(view_);  // If we're local we have to have a view.
+  DCHECK(window_);  // If we're local we have to have a view.
   // Create the view that will house the frame now. We embed once we know the
   // url (see decidePolicyForNavigation()).
-  mus::View* child_view = view_->connection()->CreateView();
+  mus::Window* child_view = window_->connection()->CreateWindow();
   ReplicatedFrameState child_state;
   child_state.name = frame_name;
   child_state.tree_scope = scope;
@@ -335,7 +336,7 @@
   ClientPropertiesFromReplicatedFrameState(child_state, &client_properties);
 
   child_view->SetVisible(true);
-  view_->AddChild(child_view);
+  window_->AddChild(child_view);
 
   HTMLFrame::CreateParams params(frame_tree_manager_, this, child_view->id(),
                                  child_view, client_properties, nullptr);
@@ -343,7 +344,7 @@
   HTMLFrame* child_frame = GetFirstAncestorWithDelegate()
                                ->delegate_->GetHTMLFactory()
                                ->CreateHTMLFrame(&params);
-  child_frame->owned_view_.reset(new mus::ScopedViewPtr(child_view));
+  child_frame->owned_window_.reset(new mus::ScopedWindowPtr(child_view));
 
   web_view::mojom::FrameClientPtr client_ptr;
   child_frame->frame_client_binding_.reset(
@@ -395,6 +396,8 @@
            << " URL=" << GURL(info.urlRequest.url());
 
   mojo::URLRequestPtr url_request = mojo::URLRequest::From(info.urlRequest);
+  url_request->originating_time_ticks =
+      base::TimeTicks::Now().ToInternalValue();
   server_->RequestNavigate(
       WebNavigationPolicyToNavigationTarget(info.defaultPolicy), id_,
       url_request.Pass());
@@ -491,6 +494,13 @@
   // NavigationControllerImpl::RendererDidNavigate use everything passed
   // through.
   server_->DidCommitProvisionalLoad();
+
+  if (!navigation_start_time_.is_null()) {
+    frame->dataSource()->setNavigationStartTime(
+        navigation_start_time_.ToInternalValue() /
+        static_cast<double>(base::Time::kMicrosecondsPerSecond));
+    navigation_start_time_ = base::TimeTicks();
+  }
 }
 
 void HTMLFrame::didReceiveTitle(blink::WebLocalFrame* frame,
@@ -570,19 +580,19 @@
   return frame_tree_manager_->local_frame_->server_.get();
 }
 
-void HTMLFrame::SetView(mus::View* view) {
-  if (view_)
-    view_->RemoveObserver(this);
-  view_ = view;
-  if (view_)
-    view_->AddObserver(this);
+void HTMLFrame::SetWindow(mus::Window* window) {
+  if (window_)
+    window_->RemoveObserver(this);
+  window_ = window;
+  if (window_)
+    window_->AddObserver(this);
 }
 
 void HTMLFrame::CreateRootWebWidget() {
   DCHECK(!html_widget_);
-  if (view_) {
+  if (window_) {
     HTMLWidgetRootLocal::CreateParams create_params(GetApp(), global_state(),
-                                                    view_);
+                                                    window_);
     html_widget_.reset(
         delegate_->GetHTMLFactory()->CreateHTMLWidgetRootLocal(&create_params));
   } else {
@@ -594,14 +604,14 @@
   DCHECK(!html_widget_);
   DCHECK(IsLocal());
   html_widget_.reset(
-      new HTMLWidgetLocalRoot(GetApp(), global_state(), view_, local_frame));
+      new HTMLWidgetLocalRoot(GetApp(), global_state(), window_, local_frame));
 }
 
 void HTMLFrame::UpdateFocus() {
   blink::WebWidget* web_widget = GetWebWidget();
-  if (!web_widget || !view_)
+  if (!web_widget || !window_)
     return;
-  const bool is_focused = view_ && view_->HasFocus();
+  const bool is_focused = window_ && window_->HasFocus();
   web_widget->setFocus(is_focused);
   if (web_widget->isWebView())
     static_cast<blink::WebView*>(web_widget)->setIsActive(is_focused);
@@ -621,15 +631,15 @@
   // swap() ends up calling us back and we then close the frame, which deletes
   // it.
   web_frame_->swap(remote_frame);
-  if (owned_view_) {
+  if (owned_window_) {
     surface_layer_ =
           cc::SurfaceLayer::Create(cc_blink::WebLayerImpl::LayerSettings(),
                                    base::Bind(&SatisfyCallback),
                                    base::Bind(&RequireCallback));
     surface_layer_->SetSurfaceId(
-        cc::SurfaceId(owned_view_->view()->id()),
+        cc::SurfaceId(owned_window_->window()->id()),
         global_state()->device_pixel_ratio(),
-        owned_view_->view()->bounds().To<gfx::Rect>().size());
+        owned_window_->window()->bounds().To<gfx::Rect>().size());
 
     web_layer_.reset(new cc_blink::WebLayerImpl(surface_layer_));
   }
@@ -644,7 +654,7 @@
   pending_navigation_ = false;
 
   web_frame_ = remote_frame;
-  SetView(nullptr);
+  SetWindow(nullptr);
   server_.reset();
   frame_client_binding_.reset();
   if (delegate)
@@ -653,14 +663,14 @@
 
 void HTMLFrame::SwapToLocal(
     HTMLFrameDelegate* delegate,
-    mus::View* view,
+    mus::Window* window,
     const mojo::Map<mojo::String, mojo::Array<uint8_t>>& properties) {
   DVLOG(2) << "HTMLFrame::SwapToLocal this=" << this << " id=" << id_;
   CHECK(!IsLocal());
   // It doesn't make sense for the root to swap to local.
   CHECK(parent_);
   delegate_ = delegate;
-  SetView(view);
+  SetWindow(window);
   SetReplicatedFrameStateFromClientProperties(properties, &state_);
   blink::WebLocalFrame* local_web_frame =
       blink::WebLocalFrame::create(state_.tree_scope, this);
@@ -726,22 +736,23 @@
   delete this;
 }
 
-void HTMLFrame::OnViewBoundsChanged(View* view,
-                                    const Rect& old_bounds,
-                                    const Rect& new_bounds) {
-  DCHECK_EQ(view, view_);
+void HTMLFrame::OnWindowBoundsChanged(mus::Window* window,
+                                      const Rect& old_bounds,
+                                      const Rect& new_bounds) {
+  DCHECK_EQ(window, window_);
   if (html_widget_)
-    html_widget_->OnViewBoundsChanged(view);
+    html_widget_->OnWindowBoundsChanged(window);
 }
 
-void HTMLFrame::OnViewDestroyed(View* view) {
-  DCHECK_EQ(view, view_);
-  view_->RemoveObserver(this);
-  view_ = nullptr;
+void HTMLFrame::OnWindowDestroyed(mus::Window* window) {
+  DCHECK_EQ(window, window_);
+  window_->RemoveObserver(this);
+  window_ = nullptr;
   Close();
 }
 
-void HTMLFrame::OnViewInputEvent(View* view, const mojo::EventPtr& event) {
+void HTMLFrame::OnWindowInputEvent(mus::Window* window,
+                                   const mojo::EventPtr& event) {
   if (event->pointer_data && event->pointer_data->location) {
     // Blink expects coordintes to be in DIPs.
     event->pointer_data->location->x /= global_state()->device_pixel_ratio();
@@ -776,16 +787,17 @@
     web_widget->handleInputEvent(*web_event);
 }
 
-void HTMLFrame::OnViewFocusChanged(mus::View* gained_focus,
-                                   mus::View* lost_focus) {
+void HTMLFrame::OnWindowFocusChanged(mus::Window* gained_focus,
+                                     mus::Window* lost_focus) {
   UpdateFocus();
 }
 
 void HTMLFrame::OnConnect(web_view::mojom::FramePtr frame,
                           uint32_t change_id,
-                          uint32_t view_id,
-                          web_view::mojom::ViewConnectType view_connect_type,
+                          uint32_t window_id,
+                          web_view::mojom::ViewConnectType window_connect_type,
                           mojo::Array<web_view::mojom::FrameDataPtr> frame_data,
+                          int64_t navigation_start_time_ticks,
                           const OnConnectCallback& callback) {
   // This is called if this frame is created by way of OnCreatedFrame().
   callback.Run();
@@ -981,7 +993,7 @@
   const gfx::Rect rect_in_pixels(gfx::ConvertRectToPixel(
       global_state()->device_pixel_ratio(), rect_in_dip));
   const mojo::RectPtr mojo_rect_in_pixels(mojo::Rect::From(rect_in_pixels));
-  view_->SetBounds(*mojo_rect_in_pixels);
+  window_->SetBounds(*mojo_rect_in_pixels);
 }
 
 void HTMLFrame::navigate(const blink::WebURLRequest& request,
@@ -1000,7 +1012,7 @@
 
 void HTMLFrame::frameRectsChanged(const blink::WebRect& frame_rect) {
   // Only the owner of view can update its size.
-  if (!owned_view_)
+  if (!owned_window_)
     return;
 
   const gfx::Rect rect_in_dip(frame_rect.x, frame_rect.y, frame_rect.width,
@@ -1008,15 +1020,15 @@
   const gfx::Rect rect_in_pixels(gfx::ConvertRectToPixel(
       global_state()->device_pixel_ratio(), rect_in_dip));
   const mojo::RectPtr mojo_rect_in_pixels(mojo::Rect::From(rect_in_pixels));
-  owned_view_->view()->SetBounds(*mojo_rect_in_pixels);
+  owned_window_->window()->SetBounds(*mojo_rect_in_pixels);
 
   if (!surface_layer_)
     return;
 
   surface_layer_->SetSurfaceId(
-      cc::SurfaceId(owned_view_->view()->id()),
+      cc::SurfaceId(owned_window_->window()->id()),
       global_state()->device_pixel_ratio(),
-      owned_view_->view()->bounds().To<gfx::Rect>().size());
+      owned_window_->window()->bounds().To<gfx::Rect>().size());
 }
 
 }  // namespace mojo
diff --git a/components/html_viewer/html_frame.h b/components/html_viewer/html_frame.h
index 2003bcc..e444f67 100644
--- a/components/html_viewer/html_frame.h
+++ b/components/html_viewer/html_frame.h
@@ -9,10 +9,11 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
 #include "cc/layers/surface_layer.h"
 #include "components/html_viewer/html_frame_tree_manager.h"
 #include "components/html_viewer/replicated_frame_state.h"
-#include "components/mus/public/cpp/view_observer.h"
+#include "components/mus/public/cpp/window_observer.h"
 #include "components/web_view/public/interfaces/frame.mojom.h"
 #include "mojo/services/tracing/public/interfaces/tracing.mojom.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
@@ -37,8 +38,8 @@
 }
 
 namespace mus {
-class ScopedViewPtr;
-class View;
+class ScopedWindowPtr;
+class Window;
 }
 
 namespace html_viewer {
@@ -69,20 +70,20 @@
 class HTMLFrame : public blink::WebFrameClient,
                   public blink::WebRemoteFrameClient,
                   public web_view::mojom::FrameClient,
-                  public mus::ViewObserver {
+                  public mus::WindowObserver {
  public:
   struct CreateParams {
     CreateParams(
         HTMLFrameTreeManager* manager,
         HTMLFrame* parent,
         uint32_t id,
-        mus::View* view,
+        mus::Window* window,
         const mojo::Map<mojo::String, mojo::Array<uint8_t>>& properties,
         HTMLFrameDelegate* delegate)
         : manager(manager),
           parent(parent),
           id(id),
-          view(view),
+          window(window),
           properties(properties),
           delegate(delegate),
           is_local_create_child(false) {}
@@ -91,7 +92,7 @@
     HTMLFrameTreeManager* manager;
     HTMLFrame* parent;
     uint32_t id;
-    mus::View* view;
+    mus::Window* window;
     const mojo::Map<mojo::String, mojo::Array<uint8_t>>& properties;
     HTMLFrameDelegate* delegate;
 
@@ -133,7 +134,7 @@
   // The mus::View this frame renders to. This is non-null for the local frame
   // the frame tree was created with as well as non-null for any frames created
   // locally.
-  mus::View* view() { return view_; }
+  mus::Window* window() { return window_; }
 
   HTMLFrameTreeManager* frame_tree_manager() { return frame_tree_manager_; }
 
@@ -147,7 +148,8 @@
   // Returns true if this or one of the frames descendants is local.
   bool HasLocalDescendant() const;
 
-  void LoadRequest(const blink::WebURLRequest& request);
+  void LoadRequest(const blink::WebURLRequest& request,
+                   base::TimeTicks navigation_start_time);
 
  protected:
   virtual ~HTMLFrame();
@@ -226,7 +228,7 @@
   // Gets the server Frame to use for this frame.
   web_view::mojom::Frame* GetServerFrame();
 
-  void SetView(mus::View* view);
+  void SetWindow(mus::Window* window);
 
   // Creates the appropriate WebWidget implementation for the Frame.
   void CreateRootWebWidget();
@@ -241,7 +243,7 @@
   // Swaps this frame from a remote frame to a local frame.
   void SwapToLocal(
       HTMLFrameDelegate* delegate,
-      mus::View* view,
+      mus::Window* window,
       const mojo::Map<mojo::String, mojo::Array<uint8_t>>& properties);
 
   // Invoked when changing the delegate. This informs the new delegate to take
@@ -261,21 +263,23 @@
   // The various frameDetached() implementations call into this.
   void FrameDetachedImpl(blink::WebFrame* web_frame);
 
-  // mus::ViewObserver methods:
-  void OnViewBoundsChanged(mus::View* view,
-                           const mojo::Rect& old_bounds,
-                           const mojo::Rect& new_bounds) override;
-  void OnViewDestroyed(mus::View* view) override;
-  void OnViewInputEvent(mus::View* view, const mojo::EventPtr& event) override;
-  void OnViewFocusChanged(mus::View* gained_focus,
-                          mus::View* lost_focus) override;
+  // mus::WindowObserver methods:
+  void OnWindowBoundsChanged(mus::Window* window,
+                             const mojo::Rect& old_bounds,
+                             const mojo::Rect& new_bounds) override;
+  void OnWindowDestroyed(mus::Window* window) override;
+  void OnWindowInputEvent(mus::Window* window,
+                          const mojo::EventPtr& event) override;
+  void OnWindowFocusChanged(mus::Window* gained_focus,
+                            mus::Window* lost_focus) override;
 
   // web_view::mojom::FrameClient:
   void OnConnect(web_view::mojom::FramePtr server,
                  uint32_t change_id,
-                 uint32_t view_id,
+                 uint32_t window_id,
                  web_view::mojom::ViewConnectType view_connect_type,
                  mojo::Array<web_view::mojom::FrameDataPtr> frame_data,
+                 int64_t navigation_start_time_ticks,
                  const OnConnectCallback& callback) override;
   void OnFrameAdded(uint32_t change_id,
                     web_view::mojom::FrameDataPtr frame_data) override;
@@ -320,7 +324,7 @@
   HTMLFrame* parent_;
   // |view_| is non-null for local frames or remote frames that were once
   // local.
-  mus::View* view_;
+  mus::Window* window_;
   // The id for this frame. If there is a view, this is the same id as the
   // view has.
   const uint32_t id_;
@@ -340,16 +344,16 @@
   ReplicatedFrameState state_;
 
   // If this frame is the result of creating a local frame
-  // (createChildFrame()), then |owned_view_| is the View initially created
-  // for the frame. While the frame is local |owned_view_| is the same as
+  // (createChildFrame()), then |owned_window_| is the View initially created
+  // for the frame. While the frame is local |owned_window_| is the same as
   // |view_|. If this frame becomes remote |view_| is set to null and
-  // |owned_view_| remains as the View initially created for the frame.
+  // |owned_window_| remains as the View initially created for the frame.
   //
   // This is done to ensure the View isn't prematurely deleted (it must exist
   // as long as the frame is valid). If the View was deleted as soon as the
   // frame was swapped to remote then the process rendering to the view would
   // be severed.
-  scoped_ptr<mus::ScopedViewPtr> owned_view_;
+  scoped_ptr<mus::ScopedWindowPtr> owned_window_;
 
   // This object is only valid in the context of performance tests.
   tracing::StartupPerformanceDataCollectorPtr
@@ -361,6 +365,8 @@
   // received response to it.
   bool pending_navigation_;
 
+  base::TimeTicks navigation_start_time_;
+
   base::WeakPtrFactory<HTMLFrame> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(HTMLFrame);
diff --git a/components/html_viewer/html_frame_apptest.cc b/components/html_viewer/html_frame_apptest.cc
index 4bfc034..d7302be4 100644
--- a/components/html_viewer/html_frame_apptest.cc
+++ b/components/html_viewer/html_frame_apptest.cc
@@ -10,11 +10,12 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/test_timeouts.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "components/html_viewer/public/interfaces/test_html_viewer.mojom.h"
-#include "components/mus/public/cpp/tests/view_manager_test_base.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
+#include "components/mus/public/cpp/tests/window_server_test_base.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/web_view/frame.h"
 #include "components/web_view/frame_connection.h"
 #include "components/web_view/frame_tree.h"
@@ -24,7 +25,7 @@
 #include "net/test/spawned_test_server/spawned_test_server.h"
 #include "third_party/mojo_services/src/accessibility/public/interfaces/accessibility.mojom.h"
 
-using mus::ViewManagerTestBase;
+using mus::WindowServerTestBase;
 using web_view::Frame;
 using web_view::FrameConnection;
 using web_view::FrameTree;
@@ -42,7 +43,7 @@
 
 void OnGotContentHandlerForRoot(bool* got_callback) {
   *got_callback = true;
-  ignore_result(ViewManagerTestBase::QuitRunLoop());
+  ignore_result(WindowServerTestBase::QuitRunLoop());
 }
 
 mojo::ApplicationConnection* ApplicationConnectionForFrame(Frame* frame) {
@@ -56,9 +57,9 @@
   std::string result;
   test_html_viewer->GetContentAsText([&result](const String& mojo_string) {
     result = mojo_string;
-    ASSERT_TRUE(ViewManagerTestBase::QuitRunLoop());
+    ASSERT_TRUE(WindowServerTestBase::QuitRunLoop());
   });
-  if (!ViewManagerTestBase::DoRunLoopWithTimeout())
+  if (!WindowServerTestBase::DoRunLoopWithTimeout())
     ADD_FAILURE() << "Timed out waiting for execute to complete";
   //  test_html_viewer.WaitForIncomingResponse();
   return result;
@@ -71,9 +72,9 @@
   scoped_ptr<base::Value> result;
   test_html_viewer->ExecuteScript(script, [&result](const String& json_string) {
     result = base::JSONReader::Read(json_string.To<std::string>());
-    ASSERT_TRUE(ViewManagerTestBase::QuitRunLoop());
+    ASSERT_TRUE(WindowServerTestBase::QuitRunLoop());
   });
-  if (!ViewManagerTestBase::DoRunLoopWithTimeout())
+  if (!WindowServerTestBase::DoRunLoopWithTimeout())
     ADD_FAILURE() << "Timed out waiting for execute to complete";
   return result.Pass();
 }
@@ -99,7 +100,7 @@
     waiting_for_frame_child_count_->frame = frame;
     waiting_for_frame_child_count_->count = count;
 
-    return ViewManagerTestBase::DoRunLoopWithTimeout();
+    return WindowServerTestBase::DoRunLoopWithTimeout();
   }
 
   // Returns true if |frame| has navigated. If |frame| hasn't navigated runs
@@ -109,7 +110,7 @@
       return true;
 
     frames_waiting_for_navigate_.insert(frame);
-    return ViewManagerTestBase::DoRunLoopWithTimeout();
+    return WindowServerTestBase::DoRunLoopWithTimeout();
   }
 
   // TestFrameTreeDelegate:
@@ -120,12 +121,12 @@
         DidChildNavigate(waiting_for_frame_child_count_->frame,
                          waiting_for_frame_child_count_->count)) {
       waiting_for_frame_child_count_.reset();
-      ASSERT_TRUE(ViewManagerTestBase::QuitRunLoop());
+      ASSERT_TRUE(WindowServerTestBase::QuitRunLoop());
     }
 
     if (frames_waiting_for_navigate_.count(frame)) {
       frames_waiting_for_navigate_.erase(frame);
-      ignore_result(ViewManagerTestBase::QuitRunLoop());
+      ignore_result(WindowServerTestBase::QuitRunLoop());
     }
   }
 
@@ -158,7 +159,7 @@
 
 }  // namespace
 
-class HTMLFrameTest : public ViewManagerTestBase {
+class HTMLFrameTest : public WindowServerTestBase {
  public:
   HTMLFrameTest() {}
   ~HTMLFrameTest() override {}
@@ -167,11 +168,11 @@
   // Creates the frame tree showing an empty page at the root and adds (via
   // script) a frame showing the same empty page.
   Frame* LoadEmptyPageAndCreateFrame() {
-    mus::View* embed_view = window_manager()->CreateView();
+    mus::Window* embed_window = window_manager()->CreateWindow();
     frame_tree_delegate_.reset(
         new TestFrameTreeDelegateImpl(application_impl()));
-    FrameConnection* root_connection =
-        InitFrameTree(embed_view, "http://127.0.0.1:%u/files/empty_page2.html");
+    FrameConnection* root_connection = InitFrameTree(
+        embed_window, "http://127.0.0.1:%u/files/empty_page2.html");
     if (!root_connection) {
       ADD_FAILURE() << "unable to establish root connection";
       return nullptr;
@@ -211,7 +212,7 @@
     return request.Pass();
   }
 
-  FrameConnection* InitFrameTree(mus::View* view,
+  FrameConnection* InitFrameTree(mus::Window* view,
                                  const std::string& url_string) {
     frame_tree_delegate_.reset(
         new TestFrameTreeDelegateImpl(application_impl()));
@@ -220,23 +221,23 @@
     frame_connection->Init(
         application_impl(), BuildRequestForURL(url_string),
         base::Bind(&OnGotContentHandlerForRoot, &got_callback));
-    ignore_result(ViewManagerTestBase::DoRunLoopWithTimeout());
+    ignore_result(WindowServerTestBase::DoRunLoopWithTimeout());
     if (!got_callback)
       return nullptr;
     FrameConnection* result = frame_connection.get();
     FrameClient* frame_client = frame_connection->frame_client();
     ViewTreeClientPtr tree_client = frame_connection->GetViewTreeClient();
-    frame_tree_.reset(
-        new FrameTree(result->GetContentHandlerID(), view, tree_client.Pass(),
-                      frame_tree_delegate_.get(), frame_client,
-                      frame_connection.Pass(), Frame::ClientPropertyMap()));
+    frame_tree_.reset(new FrameTree(
+        result->GetContentHandlerID(), view, tree_client.Pass(),
+        frame_tree_delegate_.get(), frame_client, frame_connection.Pass(),
+        Frame::ClientPropertyMap(), base::TimeTicks::Now()));
     frame_tree_delegate_->set_frame_tree(frame_tree_.get());
     return result;
   }
 
   // ViewManagerTest:
   void SetUp() override {
-    ViewManagerTestBase::SetUp();
+    WindowServerTestBase::SetUp();
 
     // Start a test server.
     http_server_.reset(new net::SpawnedTestServer(
@@ -247,7 +248,7 @@
   void TearDown() override {
     frame_tree_.reset();
     http_server_.reset();
-    ViewManagerTestBase::TearDown();
+    WindowServerTestBase::TearDown();
   }
 
   scoped_ptr<net::SpawnedTestServer> http_server_;
@@ -260,10 +261,10 @@
 };
 
 TEST_F(HTMLFrameTest, PageWithSingleFrame) {
-  mus::View* embed_view = window_manager()->CreateView();
+  mus::Window* embed_window = window_manager()->CreateWindow();
 
   FrameConnection* root_connection = InitFrameTree(
-      embed_view, "http://127.0.0.1:%u/files/page_with_single_frame.html");
+      embed_window, "http://127.0.0.1:%u/files/page_with_single_frame.html");
   ASSERT_TRUE(root_connection);
 
   ASSERT_EQ("Page with single frame",
@@ -272,9 +273,9 @@
   ASSERT_NO_FATAL_FAILURE(
       frame_tree_delegate_->WaitForChildFrameCount(frame_tree_->root(), 1u));
 
-  ASSERT_EQ(1u, embed_view->children().size());
+  ASSERT_EQ(1u, embed_window->children().size());
   Frame* child_frame =
-      frame_tree_->root()->FindFrame(embed_view->children()[0]->id());
+      frame_tree_->root()->FindFrame(embed_window->children()[0]->id());
   ASSERT_TRUE(child_frame);
 
   ASSERT_EQ("child",
@@ -285,10 +286,10 @@
 // Creates two frames. The parent navigates the child frame by way of changing
 // the location of the child frame.
 TEST_F(HTMLFrameTest, ChangeLocationOfChildFrame) {
-  mus::View* embed_view = window_manager()->CreateView();
+  mus::Window* embed_window = window_manager()->CreateWindow();
 
   ASSERT_TRUE(InitFrameTree(
-      embed_view, "http://127.0.0.1:%u/files/page_with_single_frame.html"));
+      embed_window, "http://127.0.0.1:%u/files/page_with_single_frame.html"));
 
   // page_with_single_frame contains a child frame. The child frame should
   // create a new View and Frame.
diff --git a/components/html_viewer/html_frame_tree_manager.cc b/components/html_viewer/html_frame_tree_manager.cc
index 2cefb66..e56a9a29 100644
--- a/components/html_viewer/html_frame_tree_manager.cc
+++ b/components/html_viewer/html_frame_tree_manager.cc
@@ -16,7 +16,7 @@
 #include "components/html_viewer/html_frame.h"
 #include "components/html_viewer/html_frame_delegate.h"
 #include "components/html_viewer/html_frame_tree_manager_observer.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/web_view/web_view_switches.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebRemoteFrame.h"
@@ -69,7 +69,7 @@
 // static
 HTMLFrame* HTMLFrameTreeManager::CreateFrameAndAttachToTree(
     GlobalState* global_state,
-    mus::View* view,
+    mus::Window* window,
     scoped_ptr<DocumentResourceWaiter> resource_waiter,
     HTMLFrameDelegate* delegate) {
   if (!instances_)
@@ -79,11 +79,11 @@
   web_view::mojom::FramePtr server_frame;
   mojo::Array<web_view::mojom::FrameDataPtr> frame_data;
   uint32_t change_id;
-  uint32_t view_id;
+  uint32_t window_id;
   web_view::mojom::ViewConnectType view_connect_type;
   web_view::mojom::FrameClient::OnConnectCallback on_connect_callback;
   resource_waiter->Release(&frame_client_request, &server_frame, &frame_data,
-                           &change_id, &view_id, &view_connect_type,
+                           &change_id, &window_id, &view_connect_type,
                            &on_connect_callback);
   resource_waiter.reset();
 
@@ -98,7 +98,7 @@
            << " frame_tree=" << frame_tree << " use_existing="
            << (view_connect_type ==
                web_view::mojom::VIEW_CONNECT_TYPE_USE_EXISTING)
-           << " frame_id=" << view_id;
+           << " frame_id=" << window_id;
   if (view_connect_type == web_view::mojom::VIEW_CONNECT_TYPE_USE_EXISTING &&
       !frame_tree) {
     DVLOG(1) << "was told to use existing view but do not have frame tree";
@@ -107,11 +107,11 @@
 
   if (!frame_tree) {
     frame_tree = new HTMLFrameTreeManager(global_state);
-    frame_tree->Init(delegate, view, frame_data, change_id);
+    frame_tree->Init(delegate, window, frame_data, change_id);
     (*instances_)[frame_data[0]->frame_id] = frame_tree;
   } else if (view_connect_type ==
              web_view::mojom::VIEW_CONNECT_TYPE_USE_EXISTING) {
-    HTMLFrame* existing_frame = frame_tree->root_->FindFrame(view_id);
+    HTMLFrame* existing_frame = frame_tree->root_->FindFrame(window_id);
     if (!existing_frame) {
       DVLOG(1) << "was told to use existing view but could not find view";
       return nullptr;
@@ -123,14 +123,14 @@
     existing_frame->SwapDelegate(delegate);
   } else {
     // We're going to share a frame tree. We should know about the frame.
-    CHECK(view->id() != frame_data[0]->frame_id);
-    HTMLFrame* existing_frame = frame_tree->root_->FindFrame(view->id());
+    CHECK(window->id() != frame_data[0]->frame_id);
+    HTMLFrame* existing_frame = frame_tree->root_->FindFrame(window->id());
     if (existing_frame) {
       CHECK(!existing_frame->IsLocal());
       size_t frame_data_index = 0u;
-      CHECK(FindFrameDataIndex(frame_data, view->id(), &frame_data_index));
+      CHECK(FindFrameDataIndex(frame_data, window->id(), &frame_data_index));
       const web_view::mojom::FrameDataPtr& data = frame_data[frame_data_index];
-      existing_frame->SwapToLocal(delegate, view, data->client_properties);
+      existing_frame->SwapToLocal(delegate, window, data->client_properties);
     } else {
       // If we can't find the frame and the change_id of the incoming
       // tree is before the change id we've processed, then we removed the
@@ -139,7 +139,7 @@
         return nullptr;
 
       // We removed the frame but it hasn't been acked yet.
-      if (frame_tree->pending_remove_ids_.count(view->id()))
+      if (frame_tree->pending_remove_ids_.count(window->id()))
         return nullptr;
 
       // We don't know about the frame, but should. Something is wrong.
@@ -148,7 +148,7 @@
     }
   }
 
-  HTMLFrame* frame = frame_tree->root_->FindFrame(view_id);
+  HTMLFrame* frame = frame_tree->root_->FindFrame(window_id);
   DCHECK(frame);
   frame->Bind(server_frame.Pass(), frame_client_request.Pass());
   return frame;
@@ -219,12 +219,13 @@
 
 void HTMLFrameTreeManager::Init(
     HTMLFrameDelegate* delegate,
-    mus::View* local_view,
+    mus::Window* local_window,
     const mojo::Array<web_view::mojom::FrameDataPtr>& frame_data,
     uint32_t change_id) {
   change_id_ = change_id;
-  root_ = BuildFrameTree(delegate, frame_data, local_view->id(), local_view);
-  local_frame_ = root_->FindFrame(local_view->id());
+  root_ =
+      BuildFrameTree(delegate, frame_data, local_window->id(), local_window);
+  local_frame_ = root_->FindFrame(local_window->id());
   CHECK(local_frame_);
   local_frame_->UpdateFocus();
 }
@@ -233,7 +234,7 @@
     HTMLFrameDelegate* delegate,
     const mojo::Array<web_view::mojom::FrameDataPtr>& frame_data,
     uint32_t local_frame_id,
-    mus::View* local_view) {
+    mus::Window* local_window) {
   std::vector<HTMLFrame*> parents;
   HTMLFrame* root = nullptr;
   HTMLFrame* last_frame = nullptr;
@@ -246,7 +247,7 @@
     }
     HTMLFrame::CreateParams params(this,
                                    !parents.empty() ? parents.back() : nullptr,
-                                   frame_data[i]->frame_id, local_view,
+                                   frame_data[i]->frame_id, local_window,
                                    frame_data[i]->client_properties, nullptr);
     if (frame_data[i]->frame_id == local_frame_id)
       params.delegate = delegate;
@@ -347,7 +348,7 @@
     return;
   }
 
-  // Requests to remove local frames are followed by the View being destroyed.
+  // Requests to remove local frames are followed by the Window being destroyed.
   // We handle destruction there.
   if (frame->IsLocal())
     return;
diff --git a/components/html_viewer/html_frame_tree_manager.h b/components/html_viewer/html_frame_tree_manager.h
index 8ece76d..ef6451b4 100644
--- a/components/html_viewer/html_frame_tree_manager.h
+++ b/components/html_viewer/html_frame_tree_manager.h
@@ -19,7 +19,7 @@
 }
 
 namespace mus {
-class View;
+class Window;
 }
 
 namespace html_viewer {
@@ -34,7 +34,7 @@
 // document. Some of the frames may be remote. HTMLFrameTreeManager updates its
 // state in response to changes from the server Frame, as well as changes
 // from the underlying frames. The frame tree has at least one local frame
-// that is backed by a mus::View.
+// that is backed by a mus::Window.
 class HTMLFrameTreeManager {
  public:
   // Returns a new HTMLFrame or null if a HTMLFrame does not need to be created.
@@ -42,7 +42,7 @@
   // Close() when done.
   static HTMLFrame* CreateFrameAndAttachToTree(
       GlobalState* global_state,
-      mus::View* view,
+      mus::Window* window,
       scoped_ptr<DocumentResourceWaiter> resource_waiter,
       HTMLFrameDelegate* delegate);
 
@@ -71,7 +71,7 @@
   ~HTMLFrameTreeManager();
 
   void Init(HTMLFrameDelegate* delegate,
-            mus::View* local_view,
+            mus::Window* local_window,
             const mojo::Array<web_view::mojom::FrameDataPtr>& frame_data,
             uint32_t change_id);
 
@@ -80,7 +80,7 @@
       HTMLFrameDelegate* delegate,
       const mojo::Array<web_view::mojom::FrameDataPtr>& frame_data,
       uint32_t local_frame_id,
-      mus::View* local_view);
+      mus::Window* local_window);
 
   // Returns this HTMLFrameTreeManager from |instances_|.
   void RemoveFromInstances();
diff --git a/components/html_viewer/html_widget.cc b/components/html_viewer/html_widget.cc
index 14c04742..0f34f76 100644
--- a/components/html_viewer/html_widget.cc
+++ b/components/html_viewer/html_widget.cc
@@ -10,7 +10,7 @@
 #include "components/html_viewer/stats_collection_controller.h"
 #include "components/html_viewer/web_layer_tree_view_impl.h"
 #include "components/html_viewer/web_storage_namespace_impl.h"
-#include "components/mus/public/cpp/view.h"
+#include "components/mus/public/cpp/window.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/services/tracing/public/interfaces/tracing.mojom.h"
 #include "third_party/WebKit/public/web/WebFrameWidget.h"
@@ -33,22 +33,23 @@
 
 void InitializeWebLayerTreeView(WebLayerTreeViewImpl* web_layer_tree_view,
                                 mojo::ApplicationImpl* app,
-                                mus::View* view,
+                                mus::Window* window,
                                 blink::WebWidget* widget) {
-  DCHECK(view);
+  DCHECK(window);
   mojo::URLRequestPtr request(mojo::URLRequest::New());
   request->url = mojo::String::From("mojo:mus");
   mojo::GpuPtr gpu_service;
   app->ConnectToService(request.Pass(), &gpu_service);
-  web_layer_tree_view->Initialize(gpu_service.Pass(), view, widget);
+  web_layer_tree_view->Initialize(gpu_service.Pass(), window, widget);
 }
 
-void UpdateWebViewSizeFromViewSize(mus::View* view,
+void UpdateWebViewSizeFromViewSize(mus::Window* window,
                                    blink::WebWidget* web_widget,
                                    WebLayerTreeViewImpl* web_layer_tree_view) {
-  const gfx::Size size_in_pixels(view->bounds().width, view->bounds().height);
+  const gfx::Size size_in_pixels(window->bounds().width,
+                                 window->bounds().height);
   const gfx::Size size_in_dips = gfx::ConvertSizeToDIP(
-      view->viewport_metrics().device_pixel_ratio, size_in_pixels);
+      window->viewport_metrics().device_pixel_ratio, size_in_pixels);
   web_widget->resize(
       blink::WebSize(size_in_dips.width(), size_in_dips.height()));
   web_layer_tree_view->setViewportSize(size_in_pixels);
@@ -90,31 +91,31 @@
   return web_view_;
 }
 
-void HTMLWidgetRootRemote::OnViewBoundsChanged(mus::View* view) {}
+void HTMLWidgetRootRemote::OnWindowBoundsChanged(mus::Window* window) {}
 
 // HTMLWidgetRootLocal --------------------------------------------------------
 
 HTMLWidgetRootLocal::CreateParams::CreateParams(mojo::ApplicationImpl* app,
                                                 GlobalState* global_state,
-                                                mus::View* view)
-    : app(app), global_state(global_state), view(view) {}
+                                                mus::Window* window)
+    : app(app), global_state(global_state), window(window) {}
 
 HTMLWidgetRootLocal::CreateParams::~CreateParams() {}
 
 HTMLWidgetRootLocal::HTMLWidgetRootLocal(CreateParams* create_params)
     : app_(create_params->app),
       global_state_(create_params->global_state),
-      view_(create_params->view),
+      window_(create_params->window),
       web_view_(nullptr) {
   web_view_ = blink::WebView::create(this);
-  ime_controller_.reset(new ImeController(view_, web_view_));
+  ime_controller_.reset(new ImeController(window_, web_view_));
   // Creating the widget calls initializeLayerTreeView() to create the
   // |web_layer_tree_view_impl_|. As we haven't yet assigned the |web_view_|
   // we have to set it here.
   if (web_layer_tree_view_impl_) {
-    InitializeWebLayerTreeView(web_layer_tree_view_impl_.get(), app_, view_,
+    InitializeWebLayerTreeView(web_layer_tree_view_impl_.get(), app_, window_,
                                web_view_);
-    UpdateWebViewSizeFromViewSize(view_, web_view_,
+    UpdateWebViewSizeFromViewSize(window_, web_view_,
                                   web_layer_tree_view_impl_.get());
   }
   ConfigureSettings(web_view_->settings());
@@ -169,8 +170,8 @@
   return web_view_;
 }
 
-void HTMLWidgetRootLocal::OnViewBoundsChanged(mus::View* view) {
-  UpdateWebViewSizeFromViewSize(view, web_view_,
+void HTMLWidgetRootLocal::OnWindowBoundsChanged(mus::Window* window) {
+  UpdateWebViewSizeFromViewSize(window, web_view_,
                                 web_layer_tree_view_impl_.get());
 }
 
@@ -178,19 +179,19 @@
 
 HTMLWidgetLocalRoot::HTMLWidgetLocalRoot(mojo::ApplicationImpl* app,
                                          GlobalState* global_state,
-                                         mus::View* view,
+                                         mus::Window* window,
                                          blink::WebLocalFrame* web_local_frame)
     : app_(app), global_state_(global_state), web_frame_widget_(nullptr) {
   web_frame_widget_ = blink::WebFrameWidget::create(this, web_local_frame);
-  ime_controller_.reset(new ImeController(view, web_frame_widget_));
+  ime_controller_.reset(new ImeController(window, web_frame_widget_));
   // Creating the widget calls initializeLayerTreeView() to create the
   // |web_layer_tree_view_impl_|. As we haven't yet assigned the
   // |web_frame_widget_|
   // we have to set it here.
   if (web_layer_tree_view_impl_) {
-    InitializeWebLayerTreeView(web_layer_tree_view_impl_.get(), app_, view,
+    InitializeWebLayerTreeView(web_layer_tree_view_impl_.get(), app_, window,
                                web_frame_widget_);
-    UpdateWebViewSizeFromViewSize(view, web_frame_widget_,
+    UpdateWebViewSizeFromViewSize(window, web_frame_widget_,
                                   web_layer_tree_view_impl_.get());
   }
 }
@@ -201,8 +202,8 @@
   return web_frame_widget_;
 }
 
-void HTMLWidgetLocalRoot::OnViewBoundsChanged(mus::View* view) {
-  UpdateWebViewSizeFromViewSize(view, web_frame_widget_,
+void HTMLWidgetLocalRoot::OnWindowBoundsChanged(mus::Window* window) {
+  UpdateWebViewSizeFromViewSize(window, web_frame_widget_,
                                 web_layer_tree_view_impl_.get());
 }
 
diff --git a/components/html_viewer/html_widget.h b/components/html_viewer/html_widget.h
index 21f7daa..88a2b11c 100644
--- a/components/html_viewer/html_widget.h
+++ b/components/html_viewer/html_widget.h
@@ -17,7 +17,7 @@
 }
 
 namespace mus {
-class View;
+class Window;
 }
 
 namespace html_viewer {
@@ -34,7 +34,7 @@
 
   virtual blink::WebWidget* GetWidget() = 0;
 
-  virtual void OnViewBoundsChanged(mus::View* view) = 0;
+  virtual void OnWindowBoundsChanged(mus::Window* window) = 0;
 };
 
 // Used for the root frame when the root frame is remote.
@@ -50,7 +50,7 @@
 
   // HTMLWidget:
   blink::WebWidget* GetWidget() override;
-  void OnViewBoundsChanged(mus::View* view) override;
+  void OnWindowBoundsChanged(mus::Window* window) override;
 
   blink::WebView* web_view_;
 
@@ -64,12 +64,12 @@
   struct CreateParams {
     CreateParams(mojo::ApplicationImpl* app,
                  GlobalState* global_state,
-                 mus::View* view);
+                 mus::Window* window);
     ~CreateParams();
 
     mojo::ApplicationImpl* app;
     GlobalState* global_state;
-    mus::View* view;
+    mus::Window* window;
   };
 
   HTMLWidgetRootLocal(CreateParams* create_params);
@@ -92,11 +92,11 @@
  private:
   // HTMLWidget:
   blink::WebWidget* GetWidget() override;
-  void OnViewBoundsChanged(mus::View* view) override;
+  void OnWindowBoundsChanged(mus::Window* window) override;
 
   mojo::ApplicationImpl* app_;
   GlobalState* global_state_;
-  mus::View* view_;
+  mus::Window* window_;
   blink::WebView* web_view_;
   scoped_ptr<WebLayerTreeViewImpl> web_layer_tree_view_impl_;
   scoped_ptr<ImeController> ime_controller_;
@@ -109,14 +109,14 @@
  public:
   HTMLWidgetLocalRoot(mojo::ApplicationImpl* app,
                       GlobalState* global_state,
-                      mus::View* view,
+                      mus::Window* window,
                       blink::WebLocalFrame* web_local_frame);
   ~HTMLWidgetLocalRoot() override;
 
  private:
   // HTMLWidget:
   blink::WebWidget* GetWidget() override;
-  void OnViewBoundsChanged(mus::View* view) override;
+  void OnWindowBoundsChanged(mus::Window* window) override;
 
   // WebWidgetClient:
   virtual void initializeLayerTreeView();
diff --git a/components/html_viewer/ime_controller.cc b/components/html_viewer/ime_controller.cc
index 9fe06b3..3b65a5a 100644
--- a/components/html_viewer/ime_controller.cc
+++ b/components/html_viewer/ime_controller.cc
@@ -6,14 +6,14 @@
 
 #include "components/html_viewer/blink_input_events_type_converters.h"
 #include "components/html_viewer/blink_text_input_type_converters.h"
-#include "components/mus/public/cpp/view.h"
+#include "components/mus/public/cpp/window.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "third_party/WebKit/public/web/WebWidget.h"
 
 namespace html_viewer {
 
-ImeController::ImeController(mus::View* view, blink::WebWidget* widget)
-    : view_(view), widget_(widget) {}
+ImeController::ImeController(mus::Window* window, blink::WebWidget* widget)
+    : window_(window), widget_(widget) {}
 
 ImeController::~ImeController() {}
 
@@ -65,9 +65,9 @@
     state->composition_start = new_info.compositionStart;
     state->composition_end = new_info.compositionEnd;
     if (show_ime)
-      view_->SetImeVisibility(true, state.Pass());
+      window_->SetImeVisibility(true, state.Pass());
     else
-      view_->SetTextInputState(state.Pass());
+      window_->SetTextInputState(state.Pass());
   }
 }
 
diff --git a/components/html_viewer/ime_controller.h b/components/html_viewer/ime_controller.h
index 24923ab2..740b5c5 100644
--- a/components/html_viewer/ime_controller.h
+++ b/components/html_viewer/ime_controller.h
@@ -13,7 +13,7 @@
 }
 
 namespace mus {
-class View;
+class Window;
 }
 
 namespace html_viewer {
@@ -22,7 +22,7 @@
 // handling IME related stuff.
 class ImeController {
  public:
-  ImeController(mus::View* view, blink::WebWidget* widget);
+  ImeController(mus::Window* window, blink::WebWidget* widget);
   ~ImeController();
 
   // Methods called by WebWidget overrides.
@@ -33,13 +33,13 @@
   void ShowImeIfNeeded();
 
  private:
-  // Update text input state from WebWidget to mus::View. If the focused
+  // Update text input state from WebWidget to mus::Window. If the focused
   // element is editable and |show_ime| is True, the software keyboard will be
   // shown.
   void UpdateTextInputState(bool show_ime);
 
   // Not owned objects.
-  mus::View* view_;
+  mus::Window* window_;
   blink::WebWidget* widget_;
 
   blink::WebTextInputInfo text_input_info_;
diff --git a/components/html_viewer/layout_test_content_handler_impl.cc b/components/html_viewer/layout_test_content_handler_impl.cc
index a76f294..169adae 100644
--- a/components/html_viewer/layout_test_content_handler_impl.cc
+++ b/components/html_viewer/layout_test_content_handler_impl.cc
@@ -80,7 +80,7 @@
     HTMLFrame::CreateParams* params) {
   // The test harness isn't correctly set-up for iframes yet. So return a normal
   // HTMLFrame for iframes.
-  if (params->parent || !params->view || params->view->id() != params->id)
+  if (params->parent || !params->window || params->window->id() != params->id)
     return new HTMLFrame(params);
 
   using ProxyType =
diff --git a/components/html_viewer/layout_test_html_viewer.cc b/components/html_viewer/layout_test_html_viewer.cc
index 6827feb3..3c0a72dd1 100644
--- a/components/html_viewer/layout_test_html_viewer.cc
+++ b/components/html_viewer/layout_test_html_viewer.cc
@@ -8,6 +8,7 @@
 #include "components/html_viewer/layout_test_content_handler_impl.h"
 #include "components/test_runner/web_test_interfaces.h"
 #include "components/web_view/test_runner/public/interfaces/layout_test_runner.mojom.h"
+#include "v8/include/v8.h"
 
 namespace html_viewer {
 
@@ -26,6 +27,10 @@
   test_delegate_.set_completion_callback(
       base::Bind(&LayoutTestHTMLViewer::TestFinished, base::Unretained(this)));
   test_interfaces_->SetDelegate(&test_delegate_);
+
+  // Always expose GC to layout tests.
+  std::string flags("--expose-gc");
+  v8::V8::SetFlagsFromString(flags.c_str(), static_cast<int>(flags.size()));
 }
 
 void LayoutTestHTMLViewer::TestFinished() {
diff --git a/components/html_viewer/run_all_unittests.cc b/components/html_viewer/run_all_unittests.cc
index 537e378..9a208e1 100644
--- a/components/html_viewer/run_all_unittests.cc
+++ b/components/html_viewer/run_all_unittests.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <vector>
+
 #include "base/at_exit.h"
 #include "base/bind.h"
 #include "base/path_service.h"
@@ -9,6 +11,7 @@
 #include "base/test/test_suite.h"
 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/display.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/mojo/init/ui_init.h"
 
@@ -20,11 +23,17 @@
 
 namespace {
 
+std::vector<gfx::Display> GetTestDisplays() {
+  std::vector<gfx::Display> displays(1);
+  displays[0].set_id(2000);
+  displays[0].SetScaleAndBounds(1., gfx::Rect(0, 0, 800, 600));
+  return displays;
+}
+
 class NoAtExitBaseTestSuite : public base::TestSuite {
  public:
   NoAtExitBaseTestSuite(int argc, char** argv)
-      : base::TestSuite(argc, argv, false),
-        ui_init_(gfx::Size(800, 600), 1.f) {
+      : base::TestSuite(argc, argv, false), ui_init_(GetTestDisplays()) {
 #if defined(OS_ANDROID)
     base::MemoryMappedFile::Region resource_file_region;
     int fd = base::android::OpenApkAsset("assets/html_viewer.pak",
diff --git a/components/html_viewer/web_layer_tree_view_impl.cc b/components/html_viewer/web_layer_tree_view_impl.cc
index 9b1f468..c54081e1 100644
--- a/components/html_viewer/web_layer_tree_view_impl.cc
+++ b/components/html_viewer/web_layer_tree_view_impl.cc
@@ -12,7 +12,7 @@
 #include "cc/trees/layer_tree_host.h"
 #include "components/mus/public/cpp/context_provider.h"
 #include "components/mus/public/cpp/output_surface.h"
-#include "components/mus/public/cpp/view.h"
+#include "components/mus/public/cpp/window.h"
 #include "mojo/converters/surfaces/surfaces_type_converters.h"
 #include "third_party/WebKit/public/web/WebWidget.h"
 #include "ui/gfx/buffer_types.h"
@@ -23,8 +23,8 @@
     scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     cc::TaskGraphRunner* task_graph_runner)
-    : widget_(NULL),
-      view_(NULL),
+    : widget_(nullptr),
+      window_(nullptr),
       main_thread_compositor_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       weak_factory_(this) {
   main_thread_bound_weak_ptr_ = weak_factory_.GetWeakPtr();
@@ -58,9 +58,9 @@
 }
 
 void WebLayerTreeViewImpl::Initialize(mojo::GpuPtr gpu_service,
-                                      mus::View* view,
+                                      mus::Window* window,
                                       blink::WebWidget* widget) {
-  view_ = view;
+  window_ = window;
   widget_ = widget;
   if (gpu_service) {
     mojo::CommandBufferPtr cb;
@@ -68,9 +68,9 @@
     scoped_refptr<cc::ContextProvider> context_provider(
         new mus::ContextProvider(cb.PassInterface().PassHandle()));
     output_surface_.reset(
-        new mus::OutputSurface(context_provider, view_->RequestSurface()));
+        new mus::OutputSurface(context_provider, window_->RequestSurface()));
   }
-  layer_tree_host_->SetVisible(view_->visible());
+  layer_tree_host_->SetVisible(window_->visible());
 }
 
 WebLayerTreeViewImpl::~WebLayerTreeViewImpl() {
@@ -196,8 +196,9 @@
       // viewports.
       overscrollElasticityLayer
           ? static_cast<const cc_blink::WebLayerImpl*>(
-                overscrollElasticityLayer)->layer()
-          : NULL,
+                overscrollElasticityLayer)
+                ->layer()
+          : nullptr,
       static_cast<const cc_blink::WebLayerImpl*>(pageScaleLayer)->layer(),
       static_cast<const cc_blink::WebLayerImpl*>(innerViewportScrollLayer)
           ->layer(),
@@ -206,7 +207,7 @@
       outerViewportScrollLayer
           ? static_cast<const cc_blink::WebLayerImpl*>(outerViewportScrollLayer)
                 ->layer()
-          : NULL);
+          : nullptr);
 }
 
 void WebLayerTreeViewImpl::clearViewportLayers() {
diff --git a/components/html_viewer/web_layer_tree_view_impl.h b/components/html_viewer/web_layer_tree_view_impl.h
index ed16fab..8ca4302f 100644
--- a/components/html_viewer/web_layer_tree_view_impl.h
+++ b/components/html_viewer/web_layer_tree_view_impl.h
@@ -32,10 +32,6 @@
 class GpuMemoryBufferManager;
 }
 
-namespace mojo {
-class View;
-}
-
 namespace html_viewer {
 
 class WebLayerTreeViewImpl : public blink::WebLayerTreeView,
@@ -48,7 +44,7 @@
   ~WebLayerTreeViewImpl() override;
 
   void Initialize(mojo::GpuPtr gpu_service,
-                  mus::View* view,
+                  mus::Window* window,
                   blink::WebWidget* widget);
 
   // cc::LayerTreeHostClient implementation.
@@ -112,9 +108,9 @@
   virtual void setShowScrollBottleneckRects(bool) {}
 
  private:
-  // widget_ and view_ will outlive us.
+  // widget_ and window_ will outlive us.
   blink::WebWidget* widget_;
-  mus::View* view_;
+  mus::Window* window_;
   scoped_ptr<cc::LayerTreeHost> layer_tree_host_;
   scoped_ptr<cc::OutputSurface> output_surface_;
   scoped_refptr<base::SingleThreadTaskRunner>
diff --git a/components/mus/example/common/BUILD.gn b/components/mus/example/common/BUILD.gn
index 5cb41f0..e2f9f9b9 100644
--- a/components/mus/example/common/BUILD.gn
+++ b/components/mus/example/common/BUILD.gn
@@ -21,6 +21,8 @@
     "//components/mus/public/interfaces",
     "//mojo/application/public/cpp",
     "//mojo/application/public/cpp:sources",
+    "//mojo/converters/geometry",
+    "//mojo/converters/network",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
     "//ui/views",
     "//ui/views/mus",
diff --git a/components/mus/example/common/mus_views_init.cc b/components/mus/example/common/mus_views_init.cc
index bb4087f2..6c9863d 100644
--- a/components/mus/example/common/mus_views_init.cc
+++ b/components/mus/example/common/mus_views_init.cc
@@ -4,19 +4,83 @@
 
 #include "components/mus/example/common/mus_views_init.h"
 
-#include "components/mus/public/cpp/view_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/mus/public/interfaces/view_tree.mojom.h"
 #include "components/mus/public/interfaces/window_manager.mojom.h"
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/application/public/cpp/application_impl.h"
-#include "ui/views/mus/aura_init.h"
+#include "mojo/converters/geometry/geometry_type_converters.h"
+#include "mojo/converters/network/network_type_converters.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/views/mus/native_widget_view_manager.h"
 
-MUSViewsInit::MUSViewsInit(mojo::ApplicationImpl* app) : app_(app) {}
+namespace mojo {
+
+gfx::Display::Rotation GFXRotationFromMojomRotation(
+    mus::mojom::Rotation input) {
+  switch (input) {
+    case mus::mojom::ROTATION_VALUE_0:
+      return gfx::Display::ROTATE_0;
+    case mus::mojom::ROTATION_VALUE_90:
+      return gfx::Display::ROTATE_90;
+    case mus::mojom::ROTATION_VALUE_180:
+      return gfx::Display::ROTATE_180;
+    case mus::mojom::ROTATION_VALUE_270:
+      return gfx::Display::ROTATE_270;
+  }
+  return gfx::Display::ROTATE_0;
+}
+
+template <>
+struct TypeConverter<gfx::Display, mus::mojom::DisplayPtr> {
+  static gfx::Display Convert(const mus::mojom::DisplayPtr& input) {
+    gfx::Display result;
+    result.set_id(input->id);
+    result.SetScaleAndBounds(input->device_pixel_ratio,
+                             input->bounds.To<gfx::Rect>());
+    gfx::Rect work_area(
+        gfx::ToFlooredPoint(gfx::ScalePoint(
+            gfx::Point(input->work_area->x, input->work_area->y),
+            1.0f / input->device_pixel_ratio)),
+        gfx::ScaleToFlooredSize(
+            gfx::Size(input->work_area->width, input->work_area->height),
+            1.0f / input->device_pixel_ratio));
+    result.set_work_area(work_area);
+    result.set_rotation(GFXRotationFromMojomRotation(input->rotation));
+    return result;
+  }
+};
+
+}  // namespace mojo
+
+namespace {
+
+std::vector<gfx::Display> GetDisplaysFromWindowManager(
+    mojo::ApplicationImpl* app) {
+  mus::mojom::WindowManagerPtr window_manager;
+  app->ConnectToService(mojo::URLRequest::From(std::string("mojo:example_wm")),
+                        &window_manager);
+  std::vector<gfx::Display> displays;
+  window_manager->GetDisplays(
+      [&displays](mojo::Array<mus::mojom::DisplayPtr> mojom_displays) {
+        displays = mojom_displays.To<std::vector<gfx::Display>>();
+      });
+  CHECK(window_manager.WaitForIncomingResponse());
+  return displays;
+}
+}
+
+MUSViewsInit::MUSViewsInit(mojo::ApplicationImpl* app)
+    : app_(app),
+      aura_init_(app,
+                 "example_resources.pak",
+                 GetDisplaysFromWindowManager(app)) {}
 
 MUSViewsInit::~MUSViewsInit() {}
 
-mus::View* MUSViewsInit::CreateWindow() {
+mus::Window* MUSViewsInit::CreateWindow() {
   mus::mojom::WindowManagerPtr wm;
   mojo::URLRequestPtr request(mojo::URLRequest::New());
   request->url = "mojo:example_wm";
@@ -25,10 +89,10 @@
   mojo::InterfaceRequest<mojo::ViewTreeClient> view_tree_client_request =
       GetProxy(&view_tree_client);
   wm->OpenWindow(view_tree_client.Pass());
-  mus::ViewTreeConnection* view_tree_connection =
-      mus::ViewTreeConnection::Create(
+  mus::WindowTreeConnection* view_tree_connection =
+      mus::WindowTreeConnection::Create(
           this, view_tree_client_request.Pass(),
-          mus::ViewTreeConnection::CreateType::WAIT_FOR_EMBED);
+          mus::WindowTreeConnection::CreateType::WAIT_FOR_EMBED);
   DCHECK(view_tree_connection->GetRoot());
   return view_tree_connection->GetRoot();
 }
@@ -43,14 +107,10 @@
     views::Widget::InitParams* params,
     views::internal::NativeWidgetDelegate* delegate) {}
 
-void MUSViewsInit::OnEmbed(mus::View* root) {
-  if (!aura_init_) {
-    aura_init_.reset(
-        new views::AuraInit(root, app_->shell(), "example_resources.pak"));
-  }
+void MUSViewsInit::OnEmbed(mus::Window* root) {
 }
 
-void MUSViewsInit::OnConnectionLost(mus::ViewTreeConnection* connection) {}
+void MUSViewsInit::OnConnectionLost(mus::WindowTreeConnection* connection) {}
 
 #if defined(OS_WIN)
 HICON MUSViewsInit::GetSmallWindowIcon() const {
diff --git a/components/mus/example/common/mus_views_init.h b/components/mus/example/common/mus_views_init.h
index 355b25a..a12bddc 100644
--- a/components/mus/example/common/mus_views_init.h
+++ b/components/mus/example/common/mus_views_init.h
@@ -6,7 +6,8 @@
 #define COMPONENTS_MUS_EXAMPLE_COMMON_MUS_VIEWS_INIT_H_
 
 #include "base/memory/scoped_ptr.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
+#include "ui/views/mus/aura_init.h"
 #include "ui/views/views_delegate.h"
 
 namespace mojo {
@@ -18,13 +19,14 @@
 }
 
 // Does the necessary setup to use mus, views and the example wm.
-class MUSViewsInit : public views::ViewsDelegate, public mus::ViewTreeDelegate {
+class MUSViewsInit : public views::ViewsDelegate,
+                     public mus::WindowTreeDelegate {
  public:
   explicit MUSViewsInit(mojo::ApplicationImpl* app);
   ~MUSViewsInit() override;
 
  private:
-  mus::View* CreateWindow();
+  mus::Window* CreateWindow();
 
   // views::ViewsDelegate:
   views::NativeWidget* CreateNativeWidget(
@@ -33,16 +35,16 @@
       views::Widget::InitParams* params,
       views::internal::NativeWidgetDelegate* delegate) override;
 
-  // mus::ViewTreeDelegate:
-  void OnEmbed(mus::View* root) override;
-  void OnConnectionLost(mus::ViewTreeConnection* connection) override;
+  // mus::WindowTreeDelegate:
+  void OnEmbed(mus::Window* root) override;
+  void OnConnectionLost(mus::WindowTreeConnection* connection) override;
 #if defined(OS_WIN)
   HICON GetSmallWindowIcon() const override;
 #endif
 
   mojo::ApplicationImpl* app_;
 
-  scoped_ptr<views::AuraInit> aura_init_;
+  views::AuraInit aura_init_;
 
   DISALLOW_COPY_AND_ASSIGN(MUSViewsInit);
 };
diff --git a/components/mus/example/views_examples/views_examples_application_delegate.cc b/components/mus/example/views_examples/views_examples_application_delegate.cc
index 889186cf..d02cb67 100644
--- a/components/mus/example/views_examples/views_examples_application_delegate.cc
+++ b/components/mus/example/views_examples/views_examples_application_delegate.cc
@@ -9,7 +9,6 @@
 #include "mojo/application/public/cpp/application_impl.h"
 #include "ui/views/examples/example_base.h"
 #include "ui/views/examples/examples_window.h"
-#include "ui/views/widget/widget_delegate.h"
 
 ViewsExamplesApplicationDelegate::ViewsExamplesApplicationDelegate()
     : app_(nullptr) {}
@@ -22,12 +21,6 @@
 
   mus_views_init_.reset(new MUSViewsInit(app));
 
-  // TODO(sky): total hack! This is necessary as WindowTypeLauncherView is
-  // created before AuraInit. WindowTypeLauncherView uses resources that are
-  // configured by MUSViewsInit once a View is created. By creating a Widget
-  // here we ensure the necessary state has been setup.
-  views::Widget::CreateWindow(new views::WidgetDelegateView);
-
   views::examples::ShowExamplesWindow(views::examples::DO_NOTHING_ON_CLOSE,
                                       nullptr, nullptr);
 }
diff --git a/components/mus/example/window_type_launcher/window_type_launcher.cc b/components/mus/example/window_type_launcher/window_type_launcher.cc
index e7f0d745..07eb8787 100644
--- a/components/mus/example/window_type_launcher/window_type_launcher.cc
+++ b/components/mus/example/window_type_launcher/window_type_launcher.cc
@@ -358,12 +358,6 @@
 
   mus_views_init_.reset(new MUSViewsInit(app));
 
-  // TODO(sky): total hack! This is necessary as WindowTypeLauncherView is
-  // created before AuraInit. WindowTypeLauncherView uses resources that are
-  // configured by MUSViewsInit once a View is created. By creating a Widget
-  // here we ensure the necessary state has been setup.
-  views::Widget::CreateWindow(new views::WidgetDelegateView);
-
   views::Widget* widget = new views::Widget;
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
   params.delegate = new WindowTypeLauncherView;
diff --git a/components/mus/example/wm/window_manager_application.cc b/components/mus/example/wm/window_manager_application.cc
index 289c318..79c2e0f 100644
--- a/components/mus/example/wm/window_manager_application.cc
+++ b/components/mus/example/wm/window_manager_application.cc
@@ -7,9 +7,9 @@
 #include "components/mus/example/wm/container.h"
 #include "components/mus/example/wm/window_manager_impl.h"
 #include "components/mus/public/cpp/util.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
-#include "components/mus/public/cpp/view_tree_host_factory.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_host_factory.h"
 #include "mojo/application/public/cpp/application_connection.h"
 
 WindowManagerApplication::WindowManagerApplication()
@@ -17,7 +17,7 @@
 WindowManagerApplication::~WindowManagerApplication() {}
 
 void WindowManagerApplication::Initialize(mojo::ApplicationImpl* app) {
-  mus::CreateSingleViewTreeHost(app, this, &host_);
+  mus::CreateSingleWindowTreeHost(app, this, &host_);
 }
 
 bool WindowManagerApplication::ConfigureIncomingConnection(
@@ -26,7 +26,7 @@
   return true;
 }
 
-void WindowManagerApplication::OnEmbed(mus::View* root) {
+void WindowManagerApplication::OnEmbed(mus::Window* root) {
   root_ = root;
   CreateContainers();
 
@@ -35,7 +35,7 @@
 }
 
 void WindowManagerApplication::OnConnectionLost(
-    mus::ViewTreeConnection* connection) {
+    mus::WindowTreeConnection* connection) {
   // TODO(sky): shutdown.
   NOTIMPLEMENTED();
 }
@@ -54,12 +54,12 @@
 void WindowManagerApplication::CreateContainers() {
   for (uint16 container = static_cast<uint16>(Container::ALL_USER_BACKGROUND);
        container < static_cast<uint16>(Container::COUNT); ++container) {
-    mus::View* view = root_->connection()->CreateView();
-    DCHECK_EQ(mus::LoWord(view->id()), container)
-        << "Containers must be created before other views!";
-    view->SetBounds(root_->bounds());
-    view->SetVisible(true);
-    root_->AddChild(view);
+    mus::Window* window = root_->connection()->CreateWindow();
+    DCHECK_EQ(mus::LoWord(window->id()), container)
+        << "Containers must be created before other windows!";
+    window->SetBounds(root_->bounds());
+    window->SetVisible(true);
+    root_->AddChild(window);
   }
 }
 
diff --git a/components/mus/example/wm/window_manager_application.h b/components/mus/example/wm/window_manager_application.h
index 7e73772..79d45e6 100644
--- a/components/mus/example/wm/window_manager_application.h
+++ b/components/mus/example/wm/window_manager_application.h
@@ -8,7 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
 #include "components/mus/public/interfaces/view_tree_host.mojom.h"
 #include "components/mus/public/interfaces/window_manager.mojom.h"
 #include "mojo/application/public/cpp/application_delegate.h"
@@ -16,13 +16,13 @@
 
 class WindowManagerApplication
     : public mojo::ApplicationDelegate,
-      public mus::ViewTreeDelegate,
+      public mus::WindowTreeDelegate,
       public mojo::InterfaceFactory<mus::mojom::WindowManager> {
  public:
   WindowManagerApplication();
   ~WindowManagerApplication() override;
 
-  mus::View* root() { return root_;  }
+  mus::Window* root() { return root_; }
 
   int window_count() { return window_count_; }
   void IncrementWindowCount() { ++window_count_; }
@@ -34,8 +34,8 @@
       mojo::ApplicationConnection* connection) override;
 
   // ViewTreeDelegate:
-  void OnEmbed(mus::View* root) override;
-  void OnConnectionLost(mus::ViewTreeConnection* connection) override;
+  void OnEmbed(mus::Window* root) override;
+  void OnConnectionLost(mus::WindowTreeConnection* connection) override;
 
   // InterfaceFactory<mus::mojom::WindowManager>:
   void Create(
@@ -46,7 +46,7 @@
   void CreateContainers();
 
   // nullptr until the Mus connection is established via OnEmbed().
-  mus::View* root_;
+  mus::Window* root_;
   int window_count_;
 
   mojo::ViewTreeHostPtr host_;
diff --git a/components/mus/example/wm/window_manager_impl.cc b/components/mus/example/wm/window_manager_impl.cc
index 41b29e08..256fa14 100644
--- a/components/mus/example/wm/window_manager_impl.cc
+++ b/components/mus/example/wm/window_manager_impl.cc
@@ -7,13 +7,13 @@
 #include "components/mus/example/wm/container.h"
 #include "components/mus/example/wm/window_manager_application.h"
 #include "components/mus/public/cpp/types.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
 
 namespace {
 
-mus::Id GetViewIdForContainer(mus::ViewTreeConnection* connection,
-                              Container container) {
+mus::Id GetWindowIdForContainer(mus::WindowTreeConnection* connection,
+                                Container container) {
   return connection->GetConnectionId() << 16 | static_cast<uint16>(container);
 }
 
@@ -29,29 +29,42 @@
 WindowManagerImpl::~WindowManagerImpl() {}
 
 void WindowManagerImpl::OpenWindow(mojo::ViewTreeClientPtr client) {
-  mus::View* root = state_->root();
+  mus::Window* root = state_->root();
   DCHECK(root);
-  mus::Id container_view_id = GetViewIdForContainer(root->connection(),
-                                                    Container::USER_WINDOWS);
-  mus::View* container_view = root->GetChildById(container_view_id);
+  mus::Id container_window_id =
+      GetWindowIdForContainer(root->connection(), Container::USER_WINDOWS);
+  mus::Window* container_window = root->GetChildById(container_window_id);
 
   const int width = (root->bounds().width - 240);
   const int height = (root->bounds().height - 240);
 
-  mus::View* child_view = root->connection()->CreateView();
+  mus::Window* child_window = root->connection()->CreateWindow();
   mojo::Rect bounds;
   bounds.x = 40 + (state_->window_count() % 4) * 40;
   bounds.y = 40 + (state_->window_count() % 4) * 40;
   bounds.width = width;
   bounds.height = height;
-  child_view->SetBounds(bounds);
-  container_view->AddChild(child_view);
-  child_view->Embed(client.Pass());
+  child_window->SetBounds(bounds);
+  container_window->AddChild(child_window);
+  child_window->Embed(client.Pass());
 
   state_->IncrementWindowCount();
 }
 
-void WindowManagerImpl::CenterWindow(uint32_t view_id, mojo::SizePtr size) {
+void WindowManagerImpl::CenterWindow(uint32_t window_id, mojo::SizePtr size) {
   // TODO(beng):
 }
 
+void WindowManagerImpl::GetDisplays(const GetDisplaysCallback& callback) {
+  mojo::Array<mus::mojom::DisplayPtr> displays(1);
+  displays[0] = mus::mojom::Display::New();
+  displays[0]->id = 2001;
+  displays[0]->bounds = mojo::Rect::New();
+  displays[0]->bounds->y = 0;
+  displays[0]->bounds->width = state_->root()->bounds().width;
+  displays[0]->bounds->height = state_->root()->bounds().width;
+  displays[0]->work_area = displays[0]->bounds.Clone();
+  displays[0]->device_pixel_ratio =
+      state_->root()->viewport_metrics().device_pixel_ratio;
+  callback.Run(displays.Pass());
+}
diff --git a/components/mus/example/wm/window_manager_impl.h b/components/mus/example/wm/window_manager_impl.h
index cdac569..d0a23482 100644
--- a/components/mus/example/wm/window_manager_impl.h
+++ b/components/mus/example/wm/window_manager_impl.h
@@ -20,7 +20,8 @@
  private:
   // mus::mojom::WindowManager:
   void OpenWindow(mojo::ViewTreeClientPtr client) override;
-  void CenterWindow(uint32_t view_id, mojo::SizePtr size) override;
+  void CenterWindow(uint32_t window_id, mojo::SizePtr size) override;
+  void GetDisplays(const GetDisplaysCallback& callback) override;
 
   WindowManagerApplication* state_;
   mojo::StrongBinding<mus::mojom::WindowManager> binding_;
diff --git a/components/mus/mus_app.cc b/components/mus/mus_app.cc
index 120fc79f..3cb357a 100644
--- a/components/mus/mus_app.cc
+++ b/components/mus/mus_app.cc
@@ -71,9 +71,7 @@
 
 bool MandolineUIServicesApp::ConfigureIncomingConnection(
     ApplicationConnection* connection) {
-  // MandolineUIServices
   connection->AddService<ViewTreeHostFactory>(this);
-  // GPU
   connection->AddService<Gpu>(this);
   return true;
 }
@@ -124,7 +122,7 @@
   new GpuImpl(request.Pass(), gpu_state_);
 }
 
-void MandolineUIServicesApp::CreateViewTreeHost(
+void MandolineUIServicesApp::CreateWindowTreeHost(
     mojo::InterfaceRequest<mojo::ViewTreeHost> host,
     mojo::ViewTreeHostClientPtr host_client,
     mojo::ViewTreeClientPtr tree_client) {
diff --git a/components/mus/mus_app.h b/components/mus/mus_app.h
index 9a7e8f5..c46ab0cb 100644
--- a/components/mus/mus_app.h
+++ b/components/mus/mus_app.h
@@ -75,9 +75,9 @@
               mojo::InterfaceRequest<mojo::Gpu> request) override;
 
   // mojo::ViewTreeHostFactory implementation.
-  void CreateViewTreeHost(mojo::InterfaceRequest<mojo::ViewTreeHost> host,
-                          mojo::ViewTreeHostClientPtr host_client,
-                          mojo::ViewTreeClientPtr tree_client) override;
+  void CreateWindowTreeHost(mojo::InterfaceRequest<mojo::ViewTreeHost> host,
+                            mojo::ViewTreeHostClientPtr host_client,
+                            mojo::ViewTreeClientPtr tree_client) override;
 
   mojo::WeakBindingSet<mojo::ViewTreeHostFactory> factory_bindings_;
   mojo::ApplicationImpl* app_impl_;
diff --git a/components/mus/public/cpp/BUILD.gn b/components/mus/public/cpp/BUILD.gn
index 51304e3..27bdbce 100644
--- a/components/mus/public/cpp/BUILD.gn
+++ b/components/mus/public/cpp/BUILD.gn
@@ -10,28 +10,28 @@
     "context_provider.h",
     "lib/context_provider.cc",
     "lib/output_surface.cc",
-    "lib/scoped_view_ptr.cc",
-    "lib/view.cc",
-    "lib/view_observer.cc",
-    "lib/view_private.cc",
-    "lib/view_private.h",
-    "lib/view_surface.cc",
-    "lib/view_tree_client_impl.cc",
-    "lib/view_tree_client_impl.h",
-    "lib/view_tree_delegate.cc",
-    "lib/view_tree_host_factory.cc",
+    "lib/scoped_window_ptr.cc",
+    "lib/window.cc",
+    "lib/window_observer.cc",
+    "lib/window_private.cc",
+    "lib/window_private.h",
+    "lib/window_surface.cc",
+    "lib/window_tree_client_impl.cc",
+    "lib/window_tree_client_impl.h",
+    "lib/window_tree_delegate.cc",
+    "lib/window_tree_host_factory.cc",
     "output_surface.h",
-    "scoped_view_ptr.h",
-    "view.h",
-    "view_observer.h",
-    "view_property.h",
-    "view_surface.h",
-    "view_surface_client.h",
-    "view_tracker.cc",
-    "view_tracker.h",
-    "view_tree_connection.h",
-    "view_tree_delegate.h",
-    "view_tree_host_factory.h",
+    "scoped_window_ptr.h",
+    "window.h",
+    "window_observer.h",
+    "window_property.h",
+    "window_surface.h",
+    "window_surface_client.h",
+    "window_tracker.cc",
+    "window_tracker.h",
+    "window_tree_connection.h",
+    "window_tree_delegate.h",
+    "window_tree_host_factory.h",
   ]
 
   public_deps = [
diff --git a/components/mus/public/cpp/lib/output_surface.cc b/components/mus/public/cpp/lib/output_surface.cc
index 77b2422..5b195f7 100644
--- a/components/mus/public/cpp/lib/output_surface.cc
+++ b/components/mus/public/cpp/lib/output_surface.cc
@@ -8,14 +8,14 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/compositor_frame_ack.h"
 #include "cc/output/output_surface_client.h"
-#include "components/mus/public/cpp/view_surface.h"
+#include "components/mus/public/cpp/window_surface.h"
 #include "mojo/converters/surfaces/surfaces_type_converters.h"
 
 namespace mus {
 
 OutputSurface::OutputSurface(
     const scoped_refptr<cc::ContextProvider>& context_provider,
-    scoped_ptr<mus::ViewSurface> surface)
+    scoped_ptr<mus::WindowSurface> surface)
     : cc::OutputSurface(context_provider), surface_(surface.Pass()) {
   capabilities_.delegated_rendering = true;
   capabilities_.max_frames_pending = 1;
@@ -37,7 +37,7 @@
 void OutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
   // TODO(fsamuel, rjkroege): We should probably throttle compositor frames.
   client_->DidSwapBuffers();
-  // OutputSurface owns ViewSurface, and so if OutputSurface is
+  // OutputSurface owns WindowSurface, and so if OutputSurface is
   // destroyed then SubmitCompositorFrame's callback will never get called.
   // Thus, base::Unretained is safe here.
   surface_->SubmitCompositorFrame(
@@ -46,7 +46,7 @@
 }
 
 void OutputSurface::OnResourcesReturned(
-    mus::ViewSurface* surface,
+    mus::WindowSurface* surface,
     mojo::Array<mojo::ReturnedResourcePtr> resources) {
   cc::CompositorFrameAck cfa;
   cfa.resources = resources.To<cc::ReturnedResourceArray>();
diff --git a/components/mus/public/cpp/lib/scoped_view_ptr.cc b/components/mus/public/cpp/lib/scoped_view_ptr.cc
deleted file mode 100644
index 4c41709..0000000
--- a/components/mus/public/cpp/lib/scoped_view_ptr.cc
+++ /dev/null
@@ -1,44 +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 "components/mus/public/cpp/scoped_view_ptr.h"
-
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_observer.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
-
-namespace mus {
-
-ScopedViewPtr::ScopedViewPtr(View* view) : view_(view) {
-  view_->AddObserver(this);
-}
-
-ScopedViewPtr::~ScopedViewPtr() {
-  if (view_)
-    DeleteViewOrViewManager(view_);
-  DetachFromView();
-}
-
-// static
-void ScopedViewPtr::DeleteViewOrViewManager(View* view) {
-  if (view->connection()->GetRoot() == view)
-    delete view->connection();
-  else
-    view->Destroy();
-}
-
-void ScopedViewPtr::DetachFromView() {
-  if (!view_)
-    return;
-
-  view_->RemoveObserver(this);
-  view_ = nullptr;
-}
-
-void ScopedViewPtr::OnViewDestroying(View* view) {
-  DCHECK_EQ(view_, view);
-  DetachFromView();
-}
-
-}  // namespace mus
diff --git a/components/mus/public/cpp/lib/scoped_window_ptr.cc b/components/mus/public/cpp/lib/scoped_window_ptr.cc
new file mode 100644
index 0000000..cf734cb
--- /dev/null
+++ b/components/mus/public/cpp/lib/scoped_window_ptr.cc
@@ -0,0 +1,44 @@
+// 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 "components/mus/public/cpp/scoped_window_ptr.h"
+
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+
+namespace mus {
+
+ScopedWindowPtr::ScopedWindowPtr(Window* window) : window_(window) {
+  window_->AddObserver(this);
+}
+
+ScopedWindowPtr::~ScopedWindowPtr() {
+  if (window_)
+    DeleteWindowOrWindowManager(window_);
+  DetachFromWindow();
+}
+
+// static
+void ScopedWindowPtr::DeleteWindowOrWindowManager(Window* window) {
+  if (window->connection()->GetRoot() == window)
+    delete window->connection();
+  else
+    window->Destroy();
+}
+
+void ScopedWindowPtr::DetachFromWindow() {
+  if (!window_)
+    return;
+
+  window_->RemoveObserver(this);
+  window_ = nullptr;
+}
+
+void ScopedWindowPtr::OnWindowDestroying(Window* window) {
+  DCHECK_EQ(window_, window);
+  DetachFromWindow();
+}
+
+}  // namespace mus
diff --git a/components/mus/public/cpp/lib/view.cc b/components/mus/public/cpp/lib/view.cc
deleted file mode 100644
index 88228eb..0000000
--- a/components/mus/public/cpp/lib/view.cc
+++ /dev/null
@@ -1,615 +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 "components/mus/public/cpp/view.h"
-
-#include <set>
-#include <string>
-
-#include "base/bind.h"
-#include "components/mus/public/cpp/lib/view_private.h"
-#include "components/mus/public/cpp/lib/view_tree_client_impl.h"
-#include "components/mus/public/cpp/view_observer.h"
-#include "components/mus/public/cpp/view_surface.h"
-#include "components/mus/public/cpp/view_tracker.h"
-#include "mojo/application/public/cpp/service_provider_impl.h"
-
-namespace mus {
-
-namespace {
-
-void NotifyViewTreeChangeAtReceiver(
-    View* receiver,
-    const ViewObserver::TreeChangeParams& params,
-    bool change_applied) {
-  ViewObserver::TreeChangeParams local_params = params;
-  local_params.receiver = receiver;
-  if (change_applied) {
-    FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(receiver).observers(),
-                      OnTreeChanged(local_params));
-  } else {
-    FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(receiver).observers(),
-                      OnTreeChanging(local_params));
-  }
-}
-
-void NotifyViewTreeChangeUp(View* start_at,
-                            const ViewObserver::TreeChangeParams& params,
-                            bool change_applied) {
-  for (View* current = start_at; current; current = current->parent())
-    NotifyViewTreeChangeAtReceiver(current, params, change_applied);
-}
-
-void NotifyViewTreeChangeDown(View* start_at,
-                              const ViewObserver::TreeChangeParams& params,
-                              bool change_applied) {
-  NotifyViewTreeChangeAtReceiver(start_at, params, change_applied);
-  View::Children::const_iterator it = start_at->children().begin();
-  for (; it != start_at->children().end(); ++it)
-    NotifyViewTreeChangeDown(*it, params, change_applied);
-}
-
-void NotifyViewTreeChange(const ViewObserver::TreeChangeParams& params,
-                          bool change_applied) {
-  NotifyViewTreeChangeDown(params.target, params, change_applied);
-  if (params.old_parent)
-    NotifyViewTreeChangeUp(params.old_parent, params, change_applied);
-  if (params.new_parent)
-    NotifyViewTreeChangeUp(params.new_parent, params, change_applied);
-}
-
-class ScopedTreeNotifier {
- public:
-  ScopedTreeNotifier(View* target, View* old_parent, View* new_parent) {
-    params_.target = target;
-    params_.old_parent = old_parent;
-    params_.new_parent = new_parent;
-    NotifyViewTreeChange(params_, false);
-  }
-  ~ScopedTreeNotifier() { NotifyViewTreeChange(params_, true); }
-
- private:
-  ViewObserver::TreeChangeParams params_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier);
-};
-
-void RemoveChildImpl(View* child, View::Children* children) {
-  View::Children::iterator it =
-      std::find(children->begin(), children->end(), child);
-  if (it != children->end()) {
-    children->erase(it);
-    ViewPrivate(child).ClearParent();
-  }
-}
-
-class ScopedOrderChangedNotifier {
- public:
-  ScopedOrderChangedNotifier(View* view,
-                             View* relative_view,
-                             mojo::OrderDirection direction)
-      : view_(view), relative_view_(relative_view), direction_(direction) {
-    FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(),
-                      OnViewReordering(view_, relative_view_, direction_));
-  }
-  ~ScopedOrderChangedNotifier() {
-    FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(),
-                      OnViewReordered(view_, relative_view_, direction_));
-  }
-
- private:
-  View* view_;
-  View* relative_view_;
-  mojo::OrderDirection direction_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedOrderChangedNotifier);
-};
-
-// Returns true if the order actually changed.
-bool ReorderImpl(View::Children* children,
-                 View* view,
-                 View* relative,
-                 mojo::OrderDirection direction) {
-  DCHECK(relative);
-  DCHECK_NE(view, relative);
-  DCHECK_EQ(view->parent(), relative->parent());
-
-  const size_t child_i =
-      std::find(children->begin(), children->end(), view) - children->begin();
-  const size_t target_i =
-      std::find(children->begin(), children->end(), relative) -
-      children->begin();
-  if ((direction == mojo::ORDER_DIRECTION_ABOVE && child_i == target_i + 1) ||
-      (direction == mojo::ORDER_DIRECTION_BELOW && child_i + 1 == target_i)) {
-    return false;
-  }
-
-  ScopedOrderChangedNotifier notifier(view, relative, direction);
-
-  const size_t dest_i = direction == mojo::ORDER_DIRECTION_ABOVE
-                            ? (child_i < target_i ? target_i : target_i + 1)
-                            : (child_i < target_i ? target_i - 1 : target_i);
-  children->erase(children->begin() + child_i);
-  children->insert(children->begin() + dest_i, view);
-
-  return true;
-}
-
-class ScopedSetBoundsNotifier {
- public:
-  ScopedSetBoundsNotifier(View* view,
-                          const mojo::Rect& old_bounds,
-                          const mojo::Rect& new_bounds)
-      : view_(view), old_bounds_(old_bounds), new_bounds_(new_bounds) {
-    FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(),
-                      OnViewBoundsChanging(view_, old_bounds_, new_bounds_));
-  }
-  ~ScopedSetBoundsNotifier() {
-    FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(),
-                      OnViewBoundsChanged(view_, old_bounds_, new_bounds_));
-  }
-
- private:
-  View* view_;
-  const mojo::Rect old_bounds_;
-  const mojo::Rect new_bounds_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier);
-};
-
-// Some operations are only permitted in the connection that created the view.
-bool OwnsView(ViewTreeConnection* connection, View* view) {
-  return !connection ||
-         static_cast<ViewTreeClientImpl*>(connection)->OwnsView(view->id());
-}
-
-void EmptyEmbedCallback(bool result, ConnectionSpecificId connection_id) {}
-
-}  // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// View, public:
-
-void View::Destroy() {
-  if (!OwnsView(connection_, this))
-    return;
-
-  if (connection_)
-    static_cast<ViewTreeClientImpl*>(connection_)->DestroyView(id_);
-  while (!children_.empty()) {
-    View* child = children_.front();
-    if (!OwnsView(connection_, child)) {
-      ViewPrivate(child).ClearParent();
-      children_.erase(children_.begin());
-    } else {
-      child->Destroy();
-      DCHECK(std::find(children_.begin(), children_.end(), child) ==
-             children_.end());
-    }
-  }
-  LocalDestroy();
-}
-
-void View::SetBounds(const mojo::Rect& bounds) {
-  if (!OwnsView(connection_, this))
-    return;
-
-  if (bounds_.Equals(bounds))
-    return;
-
-  if (connection_)
-    static_cast<ViewTreeClientImpl*>(connection_)->SetBounds(id_, bounds);
-  LocalSetBounds(bounds_, bounds);
-}
-
-void View::SetVisible(bool value) {
-  if (visible_ == value)
-    return;
-
-  if (connection_)
-    static_cast<ViewTreeClientImpl*>(connection_)->SetVisible(id_, value);
-  LocalSetVisible(value);
-}
-
-scoped_ptr<ViewSurface> View::RequestSurface() {
-  mojo::SurfacePtr surface;
-  mojo::SurfaceClientPtr client;
-  mojo::InterfaceRequest<mojo::SurfaceClient> client_request =
-      GetProxy(&client);
-  static_cast<ViewTreeClientImpl*>(connection_)
-      ->RequestSurface(id_, GetProxy(&surface), client.Pass());
-  return make_scoped_ptr(
-      new ViewSurface(surface.PassInterface(), client_request.Pass()));
-}
-
-void View::SetSharedProperty(const std::string& name,
-                             const std::vector<uint8_t>* value) {
-  std::vector<uint8_t> old_value;
-  std::vector<uint8_t>* old_value_ptr = nullptr;
-  auto it = properties_.find(name);
-  if (it != properties_.end()) {
-    old_value = it->second;
-    old_value_ptr = &old_value;
-
-    if (value && old_value == *value)
-      return;
-  } else if (!value) {
-    // This property isn't set in |properties_| and |value| is NULL, so there's
-    // no change.
-    return;
-  }
-
-  if (value) {
-    properties_[name] = *value;
-  } else if (it != properties_.end()) {
-    properties_.erase(it);
-  }
-
-  // TODO: add test coverage of this (450303).
-  if (connection_) {
-    mojo::Array<uint8_t> transport_value;
-    if (value) {
-      transport_value.resize(value->size());
-      if (value->size())
-        memcpy(&transport_value.front(), &(value->front()), value->size());
-    }
-    static_cast<ViewTreeClientImpl*>(connection_)
-        ->SetProperty(id_, name, transport_value.Pass());
-  }
-
-  FOR_EACH_OBSERVER(
-      ViewObserver, observers_,
-      OnViewSharedPropertyChanged(this, name, old_value_ptr, value));
-}
-
-bool View::IsDrawn() const {
-  if (!visible_)
-    return false;
-  return parent_ ? parent_->IsDrawn() : drawn_;
-}
-
-void View::AddObserver(ViewObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void View::RemoveObserver(ViewObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-const View* View::GetRoot() const {
-  const View* root = this;
-  for (const View* parent = this; parent; parent = parent->parent())
-    root = parent;
-  return root;
-}
-
-void View::AddChild(View* child) {
-  // TODO(beng): not necessarily valid to all connections, but possibly to the
-  //             embeddee in an embedder-embeddee relationship.
-  if (connection_)
-    CHECK_EQ(child->connection(), connection_);
-  LocalAddChild(child);
-  if (connection_)
-    static_cast<ViewTreeClientImpl*>(connection_)->AddChild(child->id(), id_);
-}
-
-void View::RemoveChild(View* child) {
-  // TODO(beng): not necessarily valid to all connections, but possibly to the
-  //             embeddee in an embedder-embeddee relationship.
-  if (connection_)
-    CHECK_EQ(child->connection(), connection_);
-  LocalRemoveChild(child);
-  if (connection_) {
-    static_cast<ViewTreeClientImpl*>(connection_)
-        ->RemoveChild(child->id(), id_);
-  }
-}
-
-void View::MoveToFront() {
-  if (!parent_ || parent_->children_.back() == this)
-    return;
-  Reorder(parent_->children_.back(), mojo::ORDER_DIRECTION_ABOVE);
-}
-
-void View::MoveToBack() {
-  if (!parent_ || parent_->children_.front() == this)
-    return;
-  Reorder(parent_->children_.front(), mojo::ORDER_DIRECTION_BELOW);
-}
-
-void View::Reorder(View* relative, mojo::OrderDirection direction) {
-  if (!LocalReorder(relative, direction))
-    return;
-  if (connection_) {
-    static_cast<ViewTreeClientImpl*>(connection_)
-        ->Reorder(id_, relative->id(), direction);
-  }
-}
-
-bool View::Contains(View* child) const {
-  if (!child)
-    return false;
-  if (child == this)
-    return true;
-  if (connection_)
-    CHECK_EQ(child->connection(), connection_);
-  for (View* p = child->parent(); p; p = p->parent()) {
-    if (p == this)
-      return true;
-  }
-  return false;
-}
-
-View* View::GetChildById(Id id) {
-  if (id == id_)
-    return this;
-  // TODO(beng): this could be improved depending on how we decide to own views.
-  Children::const_iterator it = children_.begin();
-  for (; it != children_.end(); ++it) {
-    View* view = (*it)->GetChildById(id);
-    if (view)
-      return view;
-  }
-  return NULL;
-}
-
-void View::SetTextInputState(mojo::TextInputStatePtr state) {
-  if (connection_) {
-    static_cast<ViewTreeClientImpl*>(connection_)
-        ->SetViewTextInputState(id_, state.Pass());
-  }
-}
-
-void View::SetImeVisibility(bool visible, mojo::TextInputStatePtr state) {
-  // SetImeVisibility() shouldn't be used if the view is not editable.
-  DCHECK(state.is_null() || state->type != mojo::TEXT_INPUT_TYPE_NONE);
-  if (connection_) {
-    static_cast<ViewTreeClientImpl*>(connection_)
-        ->SetImeVisibility(id_, visible, state.Pass());
-  }
-}
-
-void View::SetFocus() {
-  if (connection_)
-    static_cast<ViewTreeClientImpl*>(connection_)->SetFocus(id_);
-}
-
-bool View::HasFocus() const {
-  return connection_ && connection_->GetFocusedView() == this;
-}
-
-void View::Embed(mojo::ViewTreeClientPtr client) {
-  Embed(client.Pass(), mojo::ViewTree::ACCESS_POLICY_DEFAULT,
-        base::Bind(&EmptyEmbedCallback));
-}
-
-void View::Embed(mojo::ViewTreeClientPtr client,
-                 uint32_t policy_bitmask,
-                 const EmbedCallback& callback) {
-  if (PrepareForEmbed()) {
-    static_cast<ViewTreeClientImpl*>(connection_)
-        ->Embed(id_, client.Pass(), policy_bitmask, callback);
-  } else {
-    callback.Run(false, 0);
-  }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// View, protected:
-
-namespace {
-
-mojo::ViewportMetricsPtr CreateEmptyViewportMetrics() {
-  mojo::ViewportMetricsPtr metrics = mojo::ViewportMetrics::New();
-  metrics->size_in_pixels = mojo::Size::New();
-  // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it
-  // once that's fixed.
-  return metrics.Pass();
-}
-
-}  // namespace
-
-View::View()
-    : connection_(NULL),
-      id_(static_cast<Id>(-1)),
-      parent_(NULL),
-      viewport_metrics_(CreateEmptyViewportMetrics()),
-      visible_(true),
-      drawn_(false) {}
-
-View::~View() {
-  FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDestroying(this));
-  if (parent_)
-    parent_->LocalRemoveChild(this);
-
-  // We may still have children. This can happen if the embedder destroys the
-  // root while we're still alive.
-  while (!children_.empty()) {
-    View* child = children_.front();
-    LocalRemoveChild(child);
-    DCHECK(children_.empty() || children_.front() != child);
-  }
-
-  // TODO(beng): It'd be better to do this via a destruction observer in the
-  //             ViewTreeClientImpl.
-  if (connection_)
-    static_cast<ViewTreeClientImpl*>(connection_)->RemoveView(id_);
-
-  // Clear properties.
-  for (auto& pair : prop_map_) {
-    if (pair.second.deallocator)
-      (*pair.second.deallocator)(pair.second.value);
-  }
-  prop_map_.clear();
-
-  FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDestroyed(this));
-
-  if (connection_ && connection_->GetRoot() == this)
-    static_cast<ViewTreeClientImpl*>(connection_)->OnRootDestroyed(this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// View, private:
-
-View::View(ViewTreeConnection* connection, Id id)
-    : connection_(connection),
-      id_(id),
-      parent_(nullptr),
-      viewport_metrics_(CreateEmptyViewportMetrics()),
-      visible_(false),
-      drawn_(false) {}
-
-int64 View::SetLocalPropertyInternal(const void* key,
-                                     const char* name,
-                                     PropertyDeallocator deallocator,
-                                     int64 value,
-                                     int64 default_value) {
-  int64 old = GetLocalPropertyInternal(key, default_value);
-  if (value == default_value) {
-    prop_map_.erase(key);
-  } else {
-    Value prop_value;
-    prop_value.name = name;
-    prop_value.value = value;
-    prop_value.deallocator = deallocator;
-    prop_map_[key] = prop_value;
-  }
-  FOR_EACH_OBSERVER(ViewObserver, observers_,
-                    OnViewLocalPropertyChanged(this, key, old));
-  return old;
-}
-
-int64 View::GetLocalPropertyInternal(const void* key,
-                                     int64 default_value) const {
-  std::map<const void*, Value>::const_iterator iter = prop_map_.find(key);
-  if (iter == prop_map_.end())
-    return default_value;
-  return iter->second.value;
-}
-
-void View::LocalDestroy() {
-  delete this;
-}
-
-void View::LocalAddChild(View* child) {
-  ScopedTreeNotifier notifier(child, child->parent(), this);
-  if (child->parent())
-    RemoveChildImpl(child, &child->parent_->children_);
-  children_.push_back(child);
-  child->parent_ = this;
-}
-
-void View::LocalRemoveChild(View* child) {
-  DCHECK_EQ(this, child->parent());
-  ScopedTreeNotifier notifier(child, this, NULL);
-  RemoveChildImpl(child, &children_);
-}
-
-bool View::LocalReorder(View* relative, mojo::OrderDirection direction) {
-  return ReorderImpl(&parent_->children_, this, relative, direction);
-}
-
-void View::LocalSetBounds(const mojo::Rect& old_bounds,
-                          const mojo::Rect& new_bounds) {
-  DCHECK(old_bounds.x == bounds_.x);
-  DCHECK(old_bounds.y == bounds_.y);
-  DCHECK(old_bounds.width == bounds_.width);
-  DCHECK(old_bounds.height == bounds_.height);
-  ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds);
-  bounds_ = new_bounds;
-}
-
-void View::LocalSetViewportMetrics(const mojo::ViewportMetrics& old_metrics,
-                                   const mojo::ViewportMetrics& new_metrics) {
-  // TODO(eseidel): We could check old_metrics against viewport_metrics_.
-  viewport_metrics_ = new_metrics.Clone();
-  FOR_EACH_OBSERVER(
-      ViewObserver, observers_,
-      OnViewViewportMetricsChanged(this, old_metrics, new_metrics));
-}
-
-void View::LocalSetDrawn(bool value) {
-  if (drawn_ == value)
-    return;
-
-  // As IsDrawn() is derived from |visible_| and |drawn_|, only send drawn
-  // notification is the value of IsDrawn() is really changing.
-  if (IsDrawn() == value) {
-    drawn_ = value;
-    return;
-  }
-  FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDrawnChanging(this));
-  drawn_ = value;
-  FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDrawnChanged(this));
-}
-
-void View::LocalSetVisible(bool visible) {
-  if (visible_ == visible)
-    return;
-
-  FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewVisibilityChanging(this));
-  visible_ = visible;
-  NotifyViewVisibilityChanged(this);
-}
-
-void View::NotifyViewVisibilityChanged(View* target) {
-  if (!NotifyViewVisibilityChangedDown(target)) {
-    return;  // |this| has been deleted.
-  }
-  NotifyViewVisibilityChangedUp(target);
-}
-
-bool View::NotifyViewVisibilityChangedAtReceiver(View* target) {
-  // |this| may be deleted during a call to OnViewVisibilityChanged() on one
-  // of the observers. We create an local observer for that. In that case we
-  // exit without further access to any members.
-  ViewTracker tracker;
-  tracker.Add(this);
-  FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewVisibilityChanged(target));
-  return tracker.Contains(this);
-}
-
-bool View::NotifyViewVisibilityChangedDown(View* target) {
-  if (!NotifyViewVisibilityChangedAtReceiver(target))
-    return false;  // |this| was deleted.
-  std::set<const View*> child_already_processed;
-  bool child_destroyed = false;
-  do {
-    child_destroyed = false;
-    for (View::Children::const_iterator it = children_.begin();
-         it != children_.end(); ++it) {
-      if (!child_already_processed.insert(*it).second)
-        continue;
-      if (!(*it)->NotifyViewVisibilityChangedDown(target)) {
-        // |*it| was deleted, |it| is invalid and |children_| has changed.  We
-        // exit the current for-loop and enter a new one.
-        child_destroyed = true;
-        break;
-      }
-    }
-  } while (child_destroyed);
-  return true;
-}
-
-void View::NotifyViewVisibilityChangedUp(View* target) {
-  // Start with the parent as we already notified |this|
-  // in NotifyViewVisibilityChangedDown.
-  for (View* view = parent(); view; view = view->parent()) {
-    bool ret = view->NotifyViewVisibilityChangedAtReceiver(target);
-    DCHECK(ret);
-  }
-}
-
-bool View::PrepareForEmbed() {
-  if (!OwnsView(connection_, this) &&
-      !static_cast<ViewTreeClientImpl*>(connection_)->is_embed_root()) {
-    return false;
-  }
-
-  while (!children_.empty())
-    RemoveChild(children_[0]);
-  return true;
-}
-
-}  // namespace mus
diff --git a/components/mus/public/cpp/lib/view_private.cc b/components/mus/public/cpp/lib/view_private.cc
deleted file mode 100644
index 8cee1cc..0000000
--- a/components/mus/public/cpp/lib/view_private.cc
+++ /dev/null
@@ -1,20 +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 "components/mus/public/cpp/lib/view_private.h"
-
-namespace mus {
-
-ViewPrivate::ViewPrivate(View* view) : view_(view) {
-  CHECK(view);
-}
-
-ViewPrivate::~ViewPrivate() {}
-
-// static
-View* ViewPrivate::LocalCreate() {
-  return new View;
-}
-
-}  // namespace mus
diff --git a/components/mus/public/cpp/lib/view_private.h b/components/mus/public/cpp/lib/view_private.h
deleted file mode 100644
index 56b20aa..0000000
--- a/components/mus/public/cpp/lib/view_private.h
+++ /dev/null
@@ -1,66 +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 COMPONENTS_MUS_PUBLIC_CPP_LIB_VIEW_PRIVATE_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_LIB_VIEW_PRIVATE_H_
-
-#include "components/mus/public/cpp/view.h"
-
-namespace mus {
-
-// This class is a friend of a View and contains functions to mutate internal
-// state of View.
-class ViewPrivate {
- public:
-  explicit ViewPrivate(View* view);
-  ~ViewPrivate();
-
-  // Creates and returns a new View. Caller owns the return value.
-  static View* LocalCreate();
-
-  base::ObserverList<ViewObserver>* observers() { return &view_->observers_; }
-
-  void ClearParent() { view_->parent_ = NULL; }
-
-  void set_visible(bool visible) { view_->visible_ = visible; }
-
-  void set_drawn(bool drawn) { view_->drawn_ = drawn; }
-
-  void set_id(Id id) { view_->id_ = id; }
-
-  void set_connection(ViewTreeConnection* connection) {
-    view_->connection_ = connection;
-  }
-
-  void set_properties(const std::map<std::string, std::vector<uint8_t>>& data) {
-    view_->properties_ = data;
-  }
-
-  void LocalSetViewportMetrics(const mojo::ViewportMetrics& old_metrics,
-                               const mojo::ViewportMetrics& new_metrics) {
-    view_->LocalSetViewportMetrics(new_metrics, new_metrics);
-  }
-
-  void LocalDestroy() { view_->LocalDestroy(); }
-  void LocalAddChild(View* child) { view_->LocalAddChild(child); }
-  void LocalRemoveChild(View* child) { view_->LocalRemoveChild(child); }
-  void LocalReorder(View* relative, mojo::OrderDirection direction) {
-    view_->LocalReorder(relative, direction);
-  }
-  void LocalSetBounds(const mojo::Rect& old_bounds,
-                      const mojo::Rect& new_bounds) {
-    view_->LocalSetBounds(old_bounds, new_bounds);
-  }
-  void LocalSetDrawn(bool drawn) { view_->LocalSetDrawn(drawn); }
-  void LocalSetVisible(bool visible) { view_->LocalSetVisible(visible); }
-
- private:
-  View* view_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(ViewPrivate);
-};
-
-}  // namespace mus
-
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_LIB_VIEW_PRIVATE_H_
diff --git a/components/mus/public/cpp/lib/view_tree_client_impl.cc b/components/mus/public/cpp/lib/view_tree_client_impl.cc
deleted file mode 100644
index bd2a8eb..0000000
--- a/components/mus/public/cpp/lib/view_tree_client_impl.cc
+++ /dev/null
@@ -1,449 +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 "components/mus/public/cpp/lib/view_tree_client_impl.h"
-
-#include "components/mus/public/cpp/lib/view_private.h"
-#include "components/mus/public/cpp/util.h"
-#include "components/mus/public/cpp/view_observer.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
-#include "mojo/application/public/cpp/application_impl.h"
-#include "mojo/application/public/cpp/connect.h"
-#include "mojo/application/public/cpp/service_provider_impl.h"
-#include "mojo/application/public/interfaces/service_provider.mojom.h"
-
-namespace mus {
-
-Id MakeTransportId(ConnectionSpecificId connection_id,
-                   ConnectionSpecificId local_id) {
-  return (connection_id << 16) | local_id;
-}
-
-// Helper called to construct a local view object from transport data.
-View* AddViewToConnection(ViewTreeClientImpl* client,
-                          View* parent,
-                          const mojo::ViewDataPtr& view_data) {
-  // We don't use the cto that takes a ViewTreeConnection here, since it will
-  // call back to the service and attempt to create a new view.
-  View* view = ViewPrivate::LocalCreate();
-  ViewPrivate private_view(view);
-  private_view.set_connection(client);
-  private_view.set_id(view_data->view_id);
-  private_view.set_visible(view_data->visible);
-  private_view.set_drawn(view_data->drawn);
-  private_view.LocalSetViewportMetrics(mojo::ViewportMetrics(),
-                                       *view_data->viewport_metrics);
-  private_view.set_properties(
-      view_data->properties.To<std::map<std::string, std::vector<uint8_t>>>());
-  client->AddView(view);
-  private_view.LocalSetBounds(mojo::Rect(), *view_data->bounds);
-  if (parent)
-    ViewPrivate(parent).LocalAddChild(view);
-  return view;
-}
-
-View* BuildViewTree(ViewTreeClientImpl* client,
-                    const mojo::Array<mojo::ViewDataPtr>& views,
-                    View* initial_parent) {
-  std::vector<View*> parents;
-  View* root = NULL;
-  View* last_view = NULL;
-  if (initial_parent)
-    parents.push_back(initial_parent);
-  for (size_t i = 0; i < views.size(); ++i) {
-    if (last_view && views[i]->parent_id == last_view->id()) {
-      parents.push_back(last_view);
-    } else if (!parents.empty()) {
-      while (parents.back()->id() != views[i]->parent_id)
-        parents.pop_back();
-    }
-    View* view = AddViewToConnection(
-        client, !parents.empty() ? parents.back() : NULL, views[i]);
-    if (!last_view)
-      root = view;
-    last_view = view;
-  }
-  return root;
-}
-
-ViewTreeConnection* ViewTreeConnection::Create(
-    ViewTreeDelegate* delegate,
-    mojo::InterfaceRequest<mojo::ViewTreeClient> request,
-    CreateType create_type) {
-  ViewTreeClientImpl* client = new ViewTreeClientImpl(delegate, request.Pass());
-  if (create_type == CreateType::WAIT_FOR_EMBED)
-    client->WaitForEmbed();
-  return client;
-}
-
-ViewTreeClientImpl::ViewTreeClientImpl(
-    ViewTreeDelegate* delegate,
-    mojo::InterfaceRequest<mojo::ViewTreeClient> request)
-    : connection_id_(0),
-      next_id_(1),
-      delegate_(delegate),
-      root_(nullptr),
-      capture_view_(nullptr),
-      focused_view_(nullptr),
-      activated_view_(nullptr),
-      binding_(this, request.Pass()),
-      is_embed_root_(false),
-      in_destructor_(false) {}
-
-ViewTreeClientImpl::~ViewTreeClientImpl() {
-  in_destructor_ = true;
-
-  std::vector<View*> non_owned;
-  while (!views_.empty()) {
-    IdToViewMap::iterator it = views_.begin();
-    if (OwnsView(it->second->id())) {
-      it->second->Destroy();
-    } else {
-      non_owned.push_back(it->second);
-      views_.erase(it);
-    }
-  }
-
-  // Delete the non-owned views last. In the typical case these are roots. The
-  // exception is the window manager and embed roots, which may know about
-  // other random views that it doesn't own.
-  // NOTE: we manually delete as we're a friend.
-  for (size_t i = 0; i < non_owned.size(); ++i)
-    delete non_owned[i];
-
-  delegate_->OnConnectionLost(this);
-}
-
-void ViewTreeClientImpl::WaitForEmbed() {
-  DCHECK(!root_);
-  // OnEmbed() is the first function called.
-  binding_.WaitForIncomingMethodCall();
-  // TODO(sky): deal with pipe being closed before we get OnEmbed().
-}
-
-void ViewTreeClientImpl::DestroyView(Id view_id) {
-  DCHECK(tree_);
-  tree_->DeleteView(view_id, ActionCompletedCallback());
-}
-
-void ViewTreeClientImpl::AddChild(Id child_id, Id parent_id) {
-  DCHECK(tree_);
-  tree_->AddView(parent_id, child_id, ActionCompletedCallback());
-}
-
-void ViewTreeClientImpl::RemoveChild(Id child_id, Id parent_id) {
-  DCHECK(tree_);
-  tree_->RemoveViewFromParent(child_id, ActionCompletedCallback());
-}
-
-void ViewTreeClientImpl::Reorder(Id view_id,
-                                 Id relative_view_id,
-                                 mojo::OrderDirection direction) {
-  DCHECK(tree_);
-  tree_->ReorderView(view_id, relative_view_id, direction,
-                     ActionCompletedCallback());
-}
-
-bool ViewTreeClientImpl::OwnsView(Id id) const {
-  return HiWord(id) == connection_id_;
-}
-
-void ViewTreeClientImpl::SetBounds(Id view_id, const mojo::Rect& bounds) {
-  DCHECK(tree_);
-  tree_->SetViewBounds(view_id, bounds.Clone(), ActionCompletedCallback());
-}
-
-void ViewTreeClientImpl::SetFocus(Id view_id) {
-  // In order for us to get here we had to have exposed a view, which implies we
-  // got a connection.
-  DCHECK(tree_);
-  tree_->SetFocus(view_id);
-}
-
-void ViewTreeClientImpl::SetVisible(Id view_id, bool visible) {
-  DCHECK(tree_);
-  tree_->SetViewVisibility(view_id, visible, ActionCompletedCallback());
-}
-
-void ViewTreeClientImpl::SetProperty(Id view_id,
-                                     const std::string& name,
-                                     const std::vector<uint8_t>& data) {
-  DCHECK(tree_);
-  tree_->SetViewProperty(view_id, mojo::String(name),
-                         mojo::Array<uint8_t>::From(data),
-                         ActionCompletedCallback());
-}
-
-void ViewTreeClientImpl::SetViewTextInputState(Id view_id,
-                                               mojo::TextInputStatePtr state) {
-  DCHECK(tree_);
-  tree_->SetViewTextInputState(view_id, state.Pass());
-}
-
-void ViewTreeClientImpl::SetImeVisibility(Id view_id,
-                                          bool visible,
-                                          mojo::TextInputStatePtr state) {
-  DCHECK(tree_);
-  tree_->SetImeVisibility(view_id, visible, state.Pass());
-}
-
-void ViewTreeClientImpl::Embed(Id view_id,
-                               mojo::ViewTreeClientPtr client,
-                               uint32_t policy_bitmask,
-                               const mojo::ViewTree::EmbedCallback& callback) {
-  DCHECK(tree_);
-  tree_->Embed(view_id, client.Pass(), policy_bitmask, callback);
-}
-
-void ViewTreeClientImpl::RequestSurface(
-    Id view_id,
-    mojo::InterfaceRequest<mojo::Surface> surface,
-    mojo::SurfaceClientPtr client) {
-  DCHECK(tree_);
-  tree_->RequestSurface(view_id, surface.Pass(), client.Pass());
-}
-
-void ViewTreeClientImpl::AddView(View* view) {
-  DCHECK(views_.find(view->id()) == views_.end());
-  views_[view->id()] = view;
-}
-
-void ViewTreeClientImpl::RemoveView(Id view_id) {
-  if (focused_view_ && focused_view_->id() == view_id)
-    OnViewFocused(0);
-
-  IdToViewMap::iterator it = views_.find(view_id);
-  if (it != views_.end())
-    views_.erase(it);
-}
-
-void ViewTreeClientImpl::OnRootDestroyed(View* root) {
-  DCHECK_EQ(root, root_);
-  root_ = nullptr;
-
-  // When the root is gone we can't do anything useful.
-  if (!in_destructor_)
-    delete this;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ViewTreeClientImpl, ViewTreeConnection implementation:
-
-Id ViewTreeClientImpl::CreateViewOnServer() {
-  DCHECK(tree_);
-  const Id view_id = MakeTransportId(connection_id_, next_id_++);
-  tree_->CreateView(view_id, [this](mojo::ErrorCode code) {
-    OnActionCompleted(code == mojo::ERROR_CODE_NONE);
-  });
-  return view_id;
-}
-
-View* ViewTreeClientImpl::GetRoot() {
-  return root_;
-}
-
-View* ViewTreeClientImpl::GetViewById(Id id) {
-  IdToViewMap::const_iterator it = views_.find(id);
-  return it != views_.end() ? it->second : NULL;
-}
-
-View* ViewTreeClientImpl::GetFocusedView() {
-  return focused_view_;
-}
-
-View* ViewTreeClientImpl::CreateView() {
-  View* view = new View(this, CreateViewOnServer());
-  AddView(view);
-  return view;
-}
-
-bool ViewTreeClientImpl::IsEmbedRoot() {
-  return is_embed_root_;
-}
-
-ConnectionSpecificId ViewTreeClientImpl::GetConnectionId() {
-  return connection_id_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ViewTreeClientImpl, ViewTreeClient implementation:
-
-void ViewTreeClientImpl::OnEmbed(ConnectionSpecificId connection_id,
-                                 mojo::ViewDataPtr root_data,
-                                 mojo::ViewTreePtr tree,
-                                 Id focused_view_id,
-                                 uint32 access_policy) {
-  if (tree) {
-    DCHECK(!tree_);
-    tree_ = tree.Pass();
-    tree_.set_connection_error_handler([this]() { delete this; });
-  }
-  connection_id_ = connection_id;
-  is_embed_root_ =
-      (access_policy & mojo::ViewTree::ACCESS_POLICY_EMBED_ROOT) != 0;
-
-  DCHECK(!root_);
-  root_ = AddViewToConnection(this, nullptr, root_data);
-
-  focused_view_ = GetViewById(focused_view_id);
-
-  delegate_->OnEmbed(root_);
-}
-
-void ViewTreeClientImpl::OnEmbeddedAppDisconnected(Id view_id) {
-  View* view = GetViewById(view_id);
-  if (view) {
-    FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view).observers(),
-                      OnViewEmbeddedAppDisconnected(view));
-  }
-}
-
-void ViewTreeClientImpl::OnUnembed() {
-  delegate_->OnUnembed();
-  // This will send out the various notifications.
-  delete this;
-}
-
-void ViewTreeClientImpl::OnViewBoundsChanged(Id view_id,
-                                             mojo::RectPtr old_bounds,
-                                             mojo::RectPtr new_bounds) {
-  View* view = GetViewById(view_id);
-  ViewPrivate(view).LocalSetBounds(*old_bounds, *new_bounds);
-}
-
-namespace {
-
-void SetViewportMetricsOnDecendants(View* root,
-                                    const mojo::ViewportMetrics& old_metrics,
-                                    const mojo::ViewportMetrics& new_metrics) {
-  ViewPrivate(root).LocalSetViewportMetrics(old_metrics, new_metrics);
-  const View::Children& children = root->children();
-  for (size_t i = 0; i < children.size(); ++i)
-    SetViewportMetricsOnDecendants(children[i], old_metrics, new_metrics);
-}
-}
-
-void ViewTreeClientImpl::OnViewViewportMetricsChanged(
-    mojo::ViewportMetricsPtr old_metrics,
-    mojo::ViewportMetricsPtr new_metrics) {
-  View* view = GetRoot();
-  if (view)
-    SetViewportMetricsOnDecendants(view, *old_metrics, *new_metrics);
-}
-
-void ViewTreeClientImpl::OnViewHierarchyChanged(
-    Id view_id,
-    Id new_parent_id,
-    Id old_parent_id,
-    mojo::Array<mojo::ViewDataPtr> views) {
-  View* initial_parent = views.size() ? GetViewById(views[0]->parent_id) : NULL;
-
-  const bool was_view_known = GetViewById(view_id) != nullptr;
-
-  BuildViewTree(this, views, initial_parent);
-
-  // If the view was not known, then BuildViewTree() will have created it and
-  // parented the view.
-  if (!was_view_known)
-    return;
-
-  View* new_parent = GetViewById(new_parent_id);
-  View* old_parent = GetViewById(old_parent_id);
-  View* view = GetViewById(view_id);
-  if (new_parent)
-    ViewPrivate(new_parent).LocalAddChild(view);
-  else
-    ViewPrivate(old_parent).LocalRemoveChild(view);
-}
-
-void ViewTreeClientImpl::OnViewReordered(Id view_id,
-                                         Id relative_view_id,
-                                         mojo::OrderDirection direction) {
-  View* view = GetViewById(view_id);
-  View* relative_view = GetViewById(relative_view_id);
-  if (view && relative_view)
-    ViewPrivate(view).LocalReorder(relative_view, direction);
-}
-
-void ViewTreeClientImpl::OnViewDeleted(Id view_id) {
-  View* view = GetViewById(view_id);
-  if (view)
-    ViewPrivate(view).LocalDestroy();
-}
-
-void ViewTreeClientImpl::OnViewVisibilityChanged(Id view_id, bool visible) {
-  // TODO(sky): there is a race condition here. If this client and another
-  // client change the visibility at the same time the wrong value may be set.
-  // Deal with this some how.
-  View* view = GetViewById(view_id);
-  if (view)
-    ViewPrivate(view).LocalSetVisible(visible);
-}
-
-void ViewTreeClientImpl::OnViewDrawnStateChanged(Id view_id, bool drawn) {
-  View* view = GetViewById(view_id);
-  if (view)
-    ViewPrivate(view).LocalSetDrawn(drawn);
-}
-
-void ViewTreeClientImpl::OnViewSharedPropertyChanged(
-    Id view_id,
-    const mojo::String& name,
-    mojo::Array<uint8_t> new_data) {
-  View* view = GetViewById(view_id);
-  if (view) {
-    std::vector<uint8_t> data;
-    std::vector<uint8_t>* data_ptr = NULL;
-    if (!new_data.is_null()) {
-      data = new_data.To<std::vector<uint8_t>>();
-      data_ptr = &data;
-    }
-
-    view->SetSharedProperty(name, data_ptr);
-  }
-}
-
-void ViewTreeClientImpl::OnViewInputEvent(
-    Id view_id,
-    mojo::EventPtr event,
-    const mojo::Callback<void()>& ack_callback) {
-  View* view = GetViewById(view_id);
-  if (view) {
-    FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view).observers(),
-                      OnViewInputEvent(view, event));
-  }
-  ack_callback.Run();
-}
-
-void ViewTreeClientImpl::OnViewFocused(Id focused_view_id) {
-  View* focused = GetViewById(focused_view_id);
-  View* blurred = focused_view_;
-  // Update |focused_view_| before calling any of the observers, so that the
-  // observers get the correct result from calling |View::HasFocus()|,
-  // |ViewTreeConnection::GetFocusedView()| etc.
-  focused_view_ = focused;
-  if (blurred) {
-    FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(blurred).observers(),
-                      OnViewFocusChanged(focused, blurred));
-  }
-  if (focused) {
-    FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(focused).observers(),
-                      OnViewFocusChanged(focused, blurred));
-  }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ViewTreeClientImpl, private:
-
-void ViewTreeClientImpl::OnActionCompleted(bool success) {
-  if (!change_acked_callback_.is_null())
-    change_acked_callback_.Run();
-}
-
-mojo::Callback<void(bool)> ViewTreeClientImpl::ActionCompletedCallback() {
-  return [this](bool success) { OnActionCompleted(success); };
-}
-
-}  // namespace mus
diff --git a/components/mus/public/cpp/lib/view_tree_client_impl.h b/components/mus/public/cpp/lib/view_tree_client_impl.h
deleted file mode 100644
index b532c735..0000000
--- a/components/mus/public/cpp/lib/view_tree_client_impl.h
+++ /dev/null
@@ -1,162 +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 COMPONENTS_MUS_PUBLIC_CPP_LIB_VIEW_TREE_CLIENT_IMPL_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_LIB_VIEW_TREE_CLIENT_IMPL_H_
-
-#include "components/mus/public/cpp/types.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
-#include "components/mus/public/interfaces/view_tree.mojom.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
-
-namespace mus {
-class ViewTreeConnection;
-class ViewTreeDelegate;
-
-// Manages the connection with the View Manager service.
-class ViewTreeClientImpl : public ViewTreeConnection,
-                           public mojo::ViewTreeClient {
- public:
-  ViewTreeClientImpl(ViewTreeDelegate* delegate,
-                     mojo::InterfaceRequest<mojo::ViewTreeClient> request);
-  ~ViewTreeClientImpl() override;
-
-  // Wait for OnEmbed(), returning when done.
-  void WaitForEmbed();
-
-  bool connected() const { return tree_; }
-  ConnectionSpecificId connection_id() const { return connection_id_; }
-
-  // API exposed to the view implementations that pushes local changes to the
-  // service.
-  void DestroyView(Id view_id);
-
-  // These methods take TransportIds. For views owned by the current connection,
-  // the connection id high word can be zero. In all cases, the TransportId 0x1
-  // refers to the root view.
-  void AddChild(Id child_id, Id parent_id);
-  void RemoveChild(Id child_id, Id parent_id);
-
-  void Reorder(Id view_id, Id relative_view_id, mojo::OrderDirection direction);
-
-  // Returns true if the specified view was created by this connection.
-  bool OwnsView(Id id) const;
-
-  void SetBounds(Id view_id, const mojo::Rect& bounds);
-  void SetFocus(Id view_id);
-  void SetVisible(Id view_id, bool visible);
-  void SetProperty(Id view_id,
-                   const std::string& name,
-                   const std::vector<uint8_t>& data);
-  void SetViewTextInputState(Id view_id, mojo::TextInputStatePtr state);
-  void SetImeVisibility(Id view_id,
-                        bool visible,
-                        mojo::TextInputStatePtr state);
-
-  void Embed(Id view_id,
-             mojo::ViewTreeClientPtr client,
-             uint32_t policy_bitmask,
-             const mojo::ViewTree::EmbedCallback& callback);
-
-  void RequestSurface(Id view_id,
-                      mojo::InterfaceRequest<mojo::Surface> surface,
-                      mojo::SurfaceClientPtr client);
-
-  void set_change_acked_callback(const mojo::Callback<void(void)>& callback) {
-    change_acked_callback_ = callback;
-  }
-  void ClearChangeAckedCallback() { change_acked_callback_.reset(); }
-
-  // Start/stop tracking views. While tracked, they can be retrieved via
-  // ViewTreeConnection::GetViewById.
-  void AddView(View* view);
-  void RemoveView(Id view_id);
-
-  bool is_embed_root() const { return is_embed_root_; }
-
-  // Called after the root view's observers have been notified of destruction
-  // (as the last step of ~View). This ordering ensures that the View Manager
-  // is torn down after the root.
-  void OnRootDestroyed(View* root);
-
- private:
-  typedef std::map<Id, View*> IdToViewMap;
-
-  Id CreateViewOnServer();
-
-  // Overridden from ViewTreeConnection:
-  View* GetRoot() override;
-  View* GetViewById(Id id) override;
-  View* GetFocusedView() override;
-  View* CreateView() override;
-  bool IsEmbedRoot() override;
-  ConnectionSpecificId GetConnectionId() override;
-
-  // Overridden from ViewTreeClient:
-  void OnEmbed(ConnectionSpecificId connection_id,
-               mojo::ViewDataPtr root,
-               mojo::ViewTreePtr tree,
-               Id focused_view_id,
-               uint32_t access_policy) override;
-  void OnEmbeddedAppDisconnected(Id view_id) override;
-  void OnUnembed() override;
-  void OnViewBoundsChanged(Id view_id,
-                           mojo::RectPtr old_bounds,
-                           mojo::RectPtr new_bounds) override;
-  void OnViewViewportMetricsChanged(
-      mojo::ViewportMetricsPtr old_metrics,
-      mojo::ViewportMetricsPtr new_metrics) override;
-  void OnViewHierarchyChanged(Id view_id,
-                              Id new_parent_id,
-                              Id old_parent_id,
-                              mojo::Array<mojo::ViewDataPtr> views) override;
-  void OnViewReordered(Id view_id,
-                       Id relative_view_id,
-                       mojo::OrderDirection direction) override;
-  void OnViewDeleted(Id view_id) override;
-  void OnViewVisibilityChanged(Id view_id, bool visible) override;
-  void OnViewDrawnStateChanged(Id view_id, bool drawn) override;
-  void OnViewSharedPropertyChanged(Id view_id,
-                                   const mojo::String& name,
-                                   mojo::Array<uint8_t> new_data) override;
-  void OnViewInputEvent(Id view_id,
-                        mojo::EventPtr event,
-                        const mojo::Callback<void()>& callback) override;
-  void OnViewFocused(Id focused_view_id) override;
-
-  void RootDestroyed(View* root);
-
-  void OnActionCompleted(bool success);
-
-  mojo::Callback<void(bool)> ActionCompletedCallback();
-
-  ConnectionSpecificId connection_id_;
-  ConnectionSpecificId next_id_;
-
-  mojo::Callback<void(void)> change_acked_callback_;
-
-  ViewTreeDelegate* delegate_;
-
-  View* root_;
-
-  IdToViewMap views_;
-
-  View* capture_view_;
-  View* focused_view_;
-  View* activated_view_;
-
-  mojo::Binding<ViewTreeClient> binding_;
-  mojo::ViewTreePtr tree_;
-
-  bool is_embed_root_;
-
-  bool in_destructor_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTreeClientImpl);
-};
-
-}  // namespace mus
-
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_LIB_VIEW_TREE_CLIENT_IMPL_H_
diff --git a/components/mus/public/cpp/lib/view_tree_host_factory.cc b/components/mus/public/cpp/lib/view_tree_host_factory.cc
deleted file mode 100644
index 4f649fe..0000000
--- a/components/mus/public/cpp/lib/view_tree_host_factory.cc
+++ /dev/null
@@ -1,36 +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 "components/mus/public/cpp/view_tree_host_factory.h"
-
-#include "components/mus/public/cpp/view_tree_connection.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
-#include "mojo/application/public/cpp/application_impl.h"
-
-namespace mus {
-
-void CreateViewTreeHost(mojo::ViewTreeHostFactory* factory,
-                        mojo::ViewTreeHostClientPtr host_client,
-                        ViewTreeDelegate* delegate,
-                        mojo::ViewTreeHostPtr* host) {
-  mojo::ViewTreeClientPtr tree_client;
-  ViewTreeConnection::Create(
-      delegate, GetProxy(&tree_client),
-      ViewTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
-  factory->CreateViewTreeHost(GetProxy(host), host_client.Pass(),
-                              tree_client.Pass());
-}
-
-void CreateSingleViewTreeHost(mojo::ApplicationImpl* app,
-                              ViewTreeDelegate* delegate,
-                              mojo::ViewTreeHostPtr* host) {
-  mojo::ViewTreeHostFactoryPtr factory;
-  mojo::URLRequestPtr request(mojo::URLRequest::New());
-  request->url = "mojo:mus";
-  app->ConnectToService(request.Pass(), &factory);
-  CreateViewTreeHost(factory.get(), mojo::ViewTreeHostClientPtr(), delegate,
-                     host);
-}
-
-}  // namespace mus
diff --git a/components/mus/public/cpp/lib/window.cc b/components/mus/public/cpp/lib/window.cc
new file mode 100644
index 0000000..eb4f8ca
--- /dev/null
+++ b/components/mus/public/cpp/lib/window.cc
@@ -0,0 +1,623 @@
+// 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 "components/mus/public/cpp/window.h"
+
+#include <set>
+#include <string>
+
+#include "base/bind.h"
+#include "components/mus/public/cpp/lib/window_private.h"
+#include "components/mus/public/cpp/lib/window_tree_client_impl.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_surface.h"
+#include "components/mus/public/cpp/window_tracker.h"
+#include "mojo/application/public/cpp/service_provider_impl.h"
+
+namespace mus {
+
+namespace {
+
+void NotifyWindowTreeChangeAtReceiver(
+    Window* receiver,
+    const WindowObserver::TreeChangeParams& params,
+    bool change_applied) {
+  WindowObserver::TreeChangeParams local_params = params;
+  local_params.receiver = receiver;
+  if (change_applied) {
+    FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(receiver).observers(),
+                      OnTreeChanged(local_params));
+  } else {
+    FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(receiver).observers(),
+                      OnTreeChanging(local_params));
+  }
+}
+
+void NotifyWindowTreeChangeUp(Window* start_at,
+                              const WindowObserver::TreeChangeParams& params,
+                              bool change_applied) {
+  for (Window* current = start_at; current; current = current->parent())
+    NotifyWindowTreeChangeAtReceiver(current, params, change_applied);
+}
+
+void NotifyWindowTreeChangeDown(Window* start_at,
+                                const WindowObserver::TreeChangeParams& params,
+                                bool change_applied) {
+  NotifyWindowTreeChangeAtReceiver(start_at, params, change_applied);
+  Window::Children::const_iterator it = start_at->children().begin();
+  for (; it != start_at->children().end(); ++it)
+    NotifyWindowTreeChangeDown(*it, params, change_applied);
+}
+
+void NotifyWindowTreeChange(const WindowObserver::TreeChangeParams& params,
+                            bool change_applied) {
+  NotifyWindowTreeChangeDown(params.target, params, change_applied);
+  if (params.old_parent)
+    NotifyWindowTreeChangeUp(params.old_parent, params, change_applied);
+  if (params.new_parent)
+    NotifyWindowTreeChangeUp(params.new_parent, params, change_applied);
+}
+
+class ScopedTreeNotifier {
+ public:
+  ScopedTreeNotifier(Window* target, Window* old_parent, Window* new_parent) {
+    params_.target = target;
+    params_.old_parent = old_parent;
+    params_.new_parent = new_parent;
+    NotifyWindowTreeChange(params_, false);
+  }
+  ~ScopedTreeNotifier() { NotifyWindowTreeChange(params_, true); }
+
+ private:
+  WindowObserver::TreeChangeParams params_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier);
+};
+
+void RemoveChildImpl(Window* child, Window::Children* children) {
+  Window::Children::iterator it =
+      std::find(children->begin(), children->end(), child);
+  if (it != children->end()) {
+    children->erase(it);
+    WindowPrivate(child).ClearParent();
+  }
+}
+
+class ScopedOrderChangedNotifier {
+ public:
+  ScopedOrderChangedNotifier(Window* window,
+                             Window* relative_window,
+                             mojo::OrderDirection direction)
+      : window_(window),
+        relative_window_(relative_window),
+        direction_(direction) {
+    FOR_EACH_OBSERVER(
+        WindowObserver, *WindowPrivate(window_).observers(),
+        OnWindowReordering(window_, relative_window_, direction_));
+  }
+  ~ScopedOrderChangedNotifier() {
+    FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window_).observers(),
+                      OnWindowReordered(window_, relative_window_, direction_));
+  }
+
+ private:
+  Window* window_;
+  Window* relative_window_;
+  mojo::OrderDirection direction_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedOrderChangedNotifier);
+};
+
+// Returns true if the order actually changed.
+bool ReorderImpl(Window::Children* children,
+                 Window* window,
+                 Window* relative,
+                 mojo::OrderDirection direction) {
+  DCHECK(relative);
+  DCHECK_NE(window, relative);
+  DCHECK_EQ(window->parent(), relative->parent());
+
+  const size_t child_i =
+      std::find(children->begin(), children->end(), window) - children->begin();
+  const size_t target_i =
+      std::find(children->begin(), children->end(), relative) -
+      children->begin();
+  if ((direction == mojo::ORDER_DIRECTION_ABOVE && child_i == target_i + 1) ||
+      (direction == mojo::ORDER_DIRECTION_BELOW && child_i + 1 == target_i)) {
+    return false;
+  }
+
+  ScopedOrderChangedNotifier notifier(window, relative, direction);
+
+  const size_t dest_i = direction == mojo::ORDER_DIRECTION_ABOVE
+                            ? (child_i < target_i ? target_i : target_i + 1)
+                            : (child_i < target_i ? target_i - 1 : target_i);
+  children->erase(children->begin() + child_i);
+  children->insert(children->begin() + dest_i, window);
+
+  return true;
+}
+
+class ScopedSetBoundsNotifier {
+ public:
+  ScopedSetBoundsNotifier(Window* window,
+                          const mojo::Rect& old_bounds,
+                          const mojo::Rect& new_bounds)
+      : window_(window), old_bounds_(old_bounds), new_bounds_(new_bounds) {
+    FOR_EACH_OBSERVER(
+        WindowObserver, *WindowPrivate(window_).observers(),
+        OnWindowBoundsChanging(window_, old_bounds_, new_bounds_));
+  }
+  ~ScopedSetBoundsNotifier() {
+    FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window_).observers(),
+                      OnWindowBoundsChanged(window_, old_bounds_, new_bounds_));
+  }
+
+ private:
+  Window* window_;
+  const mojo::Rect old_bounds_;
+  const mojo::Rect new_bounds_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier);
+};
+
+// Some operations are only permitted in the connection that created the window.
+bool OwnsWindow(WindowTreeConnection* connection, Window* window) {
+  return !connection ||
+         static_cast<WindowTreeClientImpl*>(connection)
+             ->OwnsWindow(window->id());
+}
+
+void EmptyEmbedCallback(bool result, ConnectionSpecificId connection_id) {}
+
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// Window, public:
+
+void Window::Destroy() {
+  if (!OwnsWindow(connection_, this))
+    return;
+
+  if (connection_)
+    static_cast<WindowTreeClientImpl*>(connection_)->DestroyWindow(id_);
+  while (!children_.empty()) {
+    Window* child = children_.front();
+    if (!OwnsWindow(connection_, child)) {
+      WindowPrivate(child).ClearParent();
+      children_.erase(children_.begin());
+    } else {
+      child->Destroy();
+      DCHECK(std::find(children_.begin(), children_.end(), child) ==
+             children_.end());
+    }
+  }
+  LocalDestroy();
+}
+
+void Window::SetBounds(const mojo::Rect& bounds) {
+  if (!OwnsWindow(connection_, this))
+    return;
+
+  if (bounds_.Equals(bounds))
+    return;
+
+  if (connection_)
+    static_cast<WindowTreeClientImpl*>(connection_)->SetBounds(id_, bounds);
+  LocalSetBounds(bounds_, bounds);
+}
+
+void Window::SetVisible(bool value) {
+  if (visible_ == value)
+    return;
+
+  if (connection_)
+    static_cast<WindowTreeClientImpl*>(connection_)->SetVisible(id_, value);
+  LocalSetVisible(value);
+}
+
+scoped_ptr<WindowSurface> Window::RequestSurface() {
+  mojo::SurfacePtr surface;
+  mojo::SurfaceClientPtr client;
+  mojo::InterfaceRequest<mojo::SurfaceClient> client_request =
+      GetProxy(&client);
+  static_cast<WindowTreeClientImpl*>(connection_)
+      ->RequestSurface(id_, GetProxy(&surface), client.Pass());
+  return make_scoped_ptr(
+      new WindowSurface(surface.PassInterface(), client_request.Pass()));
+}
+
+void Window::SetSharedProperty(const std::string& name,
+                               const std::vector<uint8_t>* value) {
+  std::vector<uint8_t> old_value;
+  std::vector<uint8_t>* old_value_ptr = nullptr;
+  auto it = properties_.find(name);
+  if (it != properties_.end()) {
+    old_value = it->second;
+    old_value_ptr = &old_value;
+
+    if (value && old_value == *value)
+      return;
+  } else if (!value) {
+    // This property isn't set in |properties_| and |value| is NULL, so there's
+    // no change.
+    return;
+  }
+
+  if (value) {
+    properties_[name] = *value;
+  } else if (it != properties_.end()) {
+    properties_.erase(it);
+  }
+
+  // TODO: add test coverage of this (450303).
+  if (connection_) {
+    mojo::Array<uint8_t> transport_value;
+    if (value) {
+      transport_value.resize(value->size());
+      if (value->size())
+        memcpy(&transport_value.front(), &(value->front()), value->size());
+    }
+    static_cast<WindowTreeClientImpl*>(connection_)
+        ->SetProperty(id_, name, transport_value.Pass());
+  }
+
+  FOR_EACH_OBSERVER(
+      WindowObserver, observers_,
+      OnWindowSharedPropertyChanged(this, name, old_value_ptr, value));
+}
+
+bool Window::IsDrawn() const {
+  if (!visible_)
+    return false;
+  return parent_ ? parent_->IsDrawn() : drawn_;
+}
+
+void Window::AddObserver(WindowObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void Window::RemoveObserver(WindowObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+const Window* Window::GetRoot() const {
+  const Window* root = this;
+  for (const Window* parent = this; parent; parent = parent->parent())
+    root = parent;
+  return root;
+}
+
+void Window::AddChild(Window* child) {
+  // TODO(beng): not necessarily valid to all connections, but possibly to the
+  //             embeddee in an embedder-embeddee relationship.
+  if (connection_)
+    CHECK_EQ(child->connection(), connection_);
+  LocalAddChild(child);
+  if (connection_)
+    static_cast<WindowTreeClientImpl*>(connection_)->AddChild(child->id(), id_);
+}
+
+void Window::RemoveChild(Window* child) {
+  // TODO(beng): not necessarily valid to all connections, but possibly to the
+  //             embeddee in an embedder-embeddee relationship.
+  if (connection_)
+    CHECK_EQ(child->connection(), connection_);
+  LocalRemoveChild(child);
+  if (connection_) {
+    static_cast<WindowTreeClientImpl*>(connection_)
+        ->RemoveChild(child->id(), id_);
+  }
+}
+
+void Window::MoveToFront() {
+  if (!parent_ || parent_->children_.back() == this)
+    return;
+  Reorder(parent_->children_.back(), mojo::ORDER_DIRECTION_ABOVE);
+}
+
+void Window::MoveToBack() {
+  if (!parent_ || parent_->children_.front() == this)
+    return;
+  Reorder(parent_->children_.front(), mojo::ORDER_DIRECTION_BELOW);
+}
+
+void Window::Reorder(Window* relative, mojo::OrderDirection direction) {
+  if (!LocalReorder(relative, direction))
+    return;
+  if (connection_) {
+    static_cast<WindowTreeClientImpl*>(connection_)
+        ->Reorder(id_, relative->id(), direction);
+  }
+}
+
+bool Window::Contains(Window* child) const {
+  if (!child)
+    return false;
+  if (child == this)
+    return true;
+  if (connection_)
+    CHECK_EQ(child->connection(), connection_);
+  for (Window* p = child->parent(); p; p = p->parent()) {
+    if (p == this)
+      return true;
+  }
+  return false;
+}
+
+Window* Window::GetChildById(Id id) {
+  if (id == id_)
+    return this;
+  // TODO(beng): this could be improved depending on how we decide to own
+  // windows.
+  Children::const_iterator it = children_.begin();
+  for (; it != children_.end(); ++it) {
+    Window* window = (*it)->GetChildById(id);
+    if (window)
+      return window;
+  }
+  return NULL;
+}
+
+void Window::SetTextInputState(mojo::TextInputStatePtr state) {
+  if (connection_) {
+    static_cast<WindowTreeClientImpl*>(connection_)
+        ->SetViewTextInputState(id_, state.Pass());
+  }
+}
+
+void Window::SetImeVisibility(bool visible, mojo::TextInputStatePtr state) {
+  // SetImeVisibility() shouldn't be used if the window is not editable.
+  DCHECK(state.is_null() || state->type != mojo::TEXT_INPUT_TYPE_NONE);
+  if (connection_) {
+    static_cast<WindowTreeClientImpl*>(connection_)
+        ->SetImeVisibility(id_, visible, state.Pass());
+  }
+}
+
+void Window::SetFocus() {
+  if (connection_)
+    static_cast<WindowTreeClientImpl*>(connection_)->SetFocus(id_);
+}
+
+bool Window::HasFocus() const {
+  return connection_ && connection_->GetFocusedWindow() == this;
+}
+
+void Window::Embed(mojo::ViewTreeClientPtr client) {
+  Embed(client.Pass(), mojo::ViewTree::ACCESS_POLICY_DEFAULT,
+        base::Bind(&EmptyEmbedCallback));
+}
+
+void Window::Embed(mojo::ViewTreeClientPtr client,
+                   uint32_t policy_bitmask,
+                   const EmbedCallback& callback) {
+  if (PrepareForEmbed()) {
+    static_cast<WindowTreeClientImpl*>(connection_)
+        ->Embed(id_, client.Pass(), policy_bitmask, callback);
+  } else {
+    callback.Run(false, 0);
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Window, protected:
+
+namespace {
+
+mojo::ViewportMetricsPtr CreateEmptyViewportMetrics() {
+  mojo::ViewportMetricsPtr metrics = mojo::ViewportMetrics::New();
+  metrics->size_in_pixels = mojo::Size::New();
+  // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it
+  // once that's fixed.
+  return metrics.Pass();
+}
+
+}  // namespace
+
+Window::Window()
+    : connection_(NULL),
+      id_(static_cast<Id>(-1)),
+      parent_(NULL),
+      viewport_metrics_(CreateEmptyViewportMetrics()),
+      visible_(true),
+      drawn_(false) {}
+
+Window::~Window() {
+  FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroying(this));
+  if (parent_)
+    parent_->LocalRemoveChild(this);
+
+  // We may still have children. This can happen if the embedder destroys the
+  // root while we're still alive.
+  while (!children_.empty()) {
+    Window* child = children_.front();
+    LocalRemoveChild(child);
+    DCHECK(children_.empty() || children_.front() != child);
+  }
+
+  // TODO(beng): It'd be better to do this via a destruction observer in the
+  //             WindowTreeClientImpl.
+  if (connection_)
+    static_cast<WindowTreeClientImpl*>(connection_)->RemoveWindow(id_);
+
+  // Clear properties.
+  for (auto& pair : prop_map_) {
+    if (pair.second.deallocator)
+      (*pair.second.deallocator)(pair.second.value);
+  }
+  prop_map_.clear();
+
+  FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroyed(this));
+
+  if (connection_ && connection_->GetRoot() == this)
+    static_cast<WindowTreeClientImpl*>(connection_)->OnRootDestroyed(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// View, private:
+
+Window::Window(WindowTreeConnection* connection, Id id)
+    : connection_(connection),
+      id_(id),
+      parent_(nullptr),
+      viewport_metrics_(CreateEmptyViewportMetrics()),
+      visible_(false),
+      drawn_(false) {}
+
+int64 Window::SetLocalPropertyInternal(const void* key,
+                                       const char* name,
+                                       PropertyDeallocator deallocator,
+                                       int64 value,
+                                       int64 default_value) {
+  int64 old = GetLocalPropertyInternal(key, default_value);
+  if (value == default_value) {
+    prop_map_.erase(key);
+  } else {
+    Value prop_value;
+    prop_value.name = name;
+    prop_value.value = value;
+    prop_value.deallocator = deallocator;
+    prop_map_[key] = prop_value;
+  }
+  FOR_EACH_OBSERVER(WindowObserver, observers_,
+                    OnWindowLocalPropertyChanged(this, key, old));
+  return old;
+}
+
+int64 Window::GetLocalPropertyInternal(const void* key,
+                                       int64 default_value) const {
+  std::map<const void*, Value>::const_iterator iter = prop_map_.find(key);
+  if (iter == prop_map_.end())
+    return default_value;
+  return iter->second.value;
+}
+
+void Window::LocalDestroy() {
+  delete this;
+}
+
+void Window::LocalAddChild(Window* child) {
+  ScopedTreeNotifier notifier(child, child->parent(), this);
+  if (child->parent())
+    RemoveChildImpl(child, &child->parent_->children_);
+  children_.push_back(child);
+  child->parent_ = this;
+}
+
+void Window::LocalRemoveChild(Window* child) {
+  DCHECK_EQ(this, child->parent());
+  ScopedTreeNotifier notifier(child, this, NULL);
+  RemoveChildImpl(child, &children_);
+}
+
+bool Window::LocalReorder(Window* relative, mojo::OrderDirection direction) {
+  return ReorderImpl(&parent_->children_, this, relative, direction);
+}
+
+void Window::LocalSetBounds(const mojo::Rect& old_bounds,
+                            const mojo::Rect& new_bounds) {
+  DCHECK(old_bounds.x == bounds_.x);
+  DCHECK(old_bounds.y == bounds_.y);
+  DCHECK(old_bounds.width == bounds_.width);
+  DCHECK(old_bounds.height == bounds_.height);
+  ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds);
+  bounds_ = new_bounds;
+}
+
+void Window::LocalSetViewportMetrics(const mojo::ViewportMetrics& old_metrics,
+                                     const mojo::ViewportMetrics& new_metrics) {
+  // TODO(eseidel): We could check old_metrics against viewport_metrics_.
+  viewport_metrics_ = new_metrics.Clone();
+  FOR_EACH_OBSERVER(
+      WindowObserver, observers_,
+      OnWindowViewportMetricsChanged(this, old_metrics, new_metrics));
+}
+
+void Window::LocalSetDrawn(bool value) {
+  if (drawn_ == value)
+    return;
+
+  // As IsDrawn() is derived from |visible_| and |drawn_|, only send drawn
+  // notification is the value of IsDrawn() is really changing.
+  if (IsDrawn() == value) {
+    drawn_ = value;
+    return;
+  }
+  FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDrawnChanging(this));
+  drawn_ = value;
+  FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDrawnChanged(this));
+}
+
+void Window::LocalSetVisible(bool visible) {
+  if (visible_ == visible)
+    return;
+
+  FOR_EACH_OBSERVER(WindowObserver, observers_,
+                    OnWindowVisibilityChanging(this));
+  visible_ = visible;
+  NotifyWindowVisibilityChanged(this);
+}
+
+void Window::NotifyWindowVisibilityChanged(Window* target) {
+  if (!NotifyWindowVisibilityChangedDown(target)) {
+    return;  // |this| has been deleted.
+  }
+  NotifyWindowVisibilityChangedUp(target);
+}
+
+bool Window::NotifyWindowVisibilityChangedAtReceiver(Window* target) {
+  // |this| may be deleted during a call to OnWindowVisibilityChanged() on one
+  // of the observers. We create an local observer for that. In that case we
+  // exit without further access to any members.
+  WindowTracker tracker;
+  tracker.Add(this);
+  FOR_EACH_OBSERVER(WindowObserver, observers_,
+                    OnWindowVisibilityChanged(target));
+  return tracker.Contains(this);
+}
+
+bool Window::NotifyWindowVisibilityChangedDown(Window* target) {
+  if (!NotifyWindowVisibilityChangedAtReceiver(target))
+    return false;  // |this| was deleted.
+  std::set<const Window*> child_already_processed;
+  bool child_destroyed = false;
+  do {
+    child_destroyed = false;
+    for (Window::Children::const_iterator it = children_.begin();
+         it != children_.end(); ++it) {
+      if (!child_already_processed.insert(*it).second)
+        continue;
+      if (!(*it)->NotifyWindowVisibilityChangedDown(target)) {
+        // |*it| was deleted, |it| is invalid and |children_| has changed.  We
+        // exit the current for-loop and enter a new one.
+        child_destroyed = true;
+        break;
+      }
+    }
+  } while (child_destroyed);
+  return true;
+}
+
+void Window::NotifyWindowVisibilityChangedUp(Window* target) {
+  // Start with the parent as we already notified |this|
+  // in NotifyWindowVisibilityChangedDown.
+  for (Window* window = parent(); window; window = window->parent()) {
+    bool ret = window->NotifyWindowVisibilityChangedAtReceiver(target);
+    DCHECK(ret);
+  }
+}
+
+bool Window::PrepareForEmbed() {
+  if (!OwnsWindow(connection_, this) &&
+      !static_cast<WindowTreeClientImpl*>(connection_)->is_embed_root()) {
+    return false;
+  }
+
+  while (!children_.empty())
+    RemoveChild(children_[0]);
+  return true;
+}
+
+}  // namespace mus
diff --git a/components/mus/public/cpp/lib/view_observer.cc b/components/mus/public/cpp/lib/window_observer.cc
similarity index 74%
rename from components/mus/public/cpp/lib/view_observer.cc
rename to components/mus/public/cpp/lib/window_observer.cc
index 40367ea..26e6507 100644
--- a/components/mus/public/cpp/lib/view_observer.cc
+++ b/components/mus/public/cpp/lib/window_observer.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/mus/public/cpp/view_observer.h"
+#include "components/mus/public/cpp/window_observer.h"
 
 namespace mus {
 
 ////////////////////////////////////////////////////////////////////////////////
-// ViewObserver, public:
+// WindowObserver, public:
 
-ViewObserver::TreeChangeParams::TreeChangeParams()
+WindowObserver::TreeChangeParams::TreeChangeParams()
     : target(nullptr),
       old_parent(nullptr),
       new_parent(nullptr),
diff --git a/components/mus/public/cpp/lib/window_private.cc b/components/mus/public/cpp/lib/window_private.cc
new file mode 100644
index 0000000..5d8dca75
--- /dev/null
+++ b/components/mus/public/cpp/lib/window_private.cc
@@ -0,0 +1,20 @@
+// 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 "components/mus/public/cpp/lib/window_private.h"
+
+namespace mus {
+
+WindowPrivate::WindowPrivate(Window* window) : window_(window) {
+  CHECK(window);
+}
+
+WindowPrivate::~WindowPrivate() {}
+
+// static
+Window* WindowPrivate::LocalCreate() {
+  return new Window;
+}
+
+}  // namespace mus
diff --git a/components/mus/public/cpp/lib/window_private.h b/components/mus/public/cpp/lib/window_private.h
new file mode 100644
index 0000000..6dd6b80
--- /dev/null
+++ b/components/mus/public/cpp/lib/window_private.h
@@ -0,0 +1,68 @@
+// 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 COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_PRIVATE_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_PRIVATE_H_
+
+#include "components/mus/public/cpp/window.h"
+
+namespace mus {
+
+// This class is a friend of a View and contains functions to mutate internal
+// state of View.
+class WindowPrivate {
+ public:
+  explicit WindowPrivate(Window* view);
+  ~WindowPrivate();
+
+  // Creates and returns a new View. Caller owns the return value.
+  static Window* LocalCreate();
+
+  base::ObserverList<WindowObserver>* observers() {
+    return &window_->observers_;
+  }
+
+  void ClearParent() { window_->parent_ = NULL; }
+
+  void set_visible(bool visible) { window_->visible_ = visible; }
+
+  void set_drawn(bool drawn) { window_->drawn_ = drawn; }
+
+  void set_id(Id id) { window_->id_ = id; }
+
+  void set_connection(WindowTreeConnection* connection) {
+    window_->connection_ = connection;
+  }
+
+  void set_properties(const std::map<std::string, std::vector<uint8_t>>& data) {
+    window_->properties_ = data;
+  }
+
+  void LocalSetViewportMetrics(const mojo::ViewportMetrics& old_metrics,
+                               const mojo::ViewportMetrics& new_metrics) {
+    window_->LocalSetViewportMetrics(new_metrics, new_metrics);
+  }
+
+  void LocalDestroy() { window_->LocalDestroy(); }
+  void LocalAddChild(Window* child) { window_->LocalAddChild(child); }
+  void LocalRemoveChild(Window* child) { window_->LocalRemoveChild(child); }
+  void LocalReorder(Window* relative, mojo::OrderDirection direction) {
+    window_->LocalReorder(relative, direction);
+  }
+  void LocalSetBounds(const mojo::Rect& old_bounds,
+                      const mojo::Rect& new_bounds) {
+    window_->LocalSetBounds(old_bounds, new_bounds);
+  }
+  void LocalSetDrawn(bool drawn) { window_->LocalSetDrawn(drawn); }
+  void LocalSetVisible(bool visible) { window_->LocalSetVisible(visible); }
+
+ private:
+  Window* window_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(WindowPrivate);
+};
+
+}  // namespace mus
+
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_PRIVATE_H_
diff --git a/components/mus/public/cpp/lib/view_surface.cc b/components/mus/public/cpp/lib/window_surface.cc
similarity index 71%
rename from components/mus/public/cpp/lib/view_surface.cc
rename to components/mus/public/cpp/lib/window_surface.cc
index 47409f7..78c4f55a 100644
--- a/components/mus/public/cpp/lib/view_surface.cc
+++ b/components/mus/public/cpp/lib/window_surface.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/mus/public/cpp/view_surface.h"
+#include "components/mus/public/cpp/window_surface.h"
 
-#include "components/mus/public/cpp/view_surface_client.h"
+#include "components/mus/public/cpp/window_surface_client.h"
 #include "mojo/converters/surfaces/surfaces_type_converters.h"
 
 namespace mus {
 
-ViewSurface::~ViewSurface() {}
+WindowSurface::~WindowSurface() {}
 
-void ViewSurface::BindToThread() {
+void WindowSurface::BindToThread() {
   DCHECK(!bound_to_thread_);
   bound_to_thread_ = true;
   surface_.Bind(surface_info_.Pass());
@@ -19,15 +19,15 @@
       new mojo::Binding<mojo::SurfaceClient>(this, client_request_.Pass()));
 }
 
-void ViewSurface::SubmitCompositorFrame(mojo::CompositorFramePtr frame,
-                                        const mojo::Closure& callback) {
+void WindowSurface::SubmitCompositorFrame(mojo::CompositorFramePtr frame,
+                                          const mojo::Closure& callback) {
   DCHECK(bound_to_thread_);
   if (!surface_)
     return;
   surface_->SubmitCompositorFrame(frame.Pass(), callback);
 }
 
-ViewSurface::ViewSurface(
+WindowSurface::WindowSurface(
     mojo::InterfacePtrInfo<mojo::Surface> surface_info,
     mojo::InterfaceRequest<mojo::SurfaceClient> client_request)
     : client_(nullptr),
@@ -35,7 +35,7 @@
       client_request_(client_request.Pass()),
       bound_to_thread_(false) {}
 
-void ViewSurface::ReturnResources(
+void WindowSurface::ReturnResources(
     mojo::Array<mojo::ReturnedResourcePtr> resources) {
   if (!client_)
     return;
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.cc b/components/mus/public/cpp/lib/window_tree_client_impl.cc
new file mode 100644
index 0000000..0fc663e
--- /dev/null
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.cc
@@ -0,0 +1,457 @@
+// 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 "components/mus/public/cpp/lib/window_tree_client_impl.h"
+
+#include "components/mus/public/cpp/lib/window_private.h"
+#include "components/mus/public/cpp/util.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/application/public/cpp/connect.h"
+#include "mojo/application/public/cpp/service_provider_impl.h"
+#include "mojo/application/public/interfaces/service_provider.mojom.h"
+
+namespace mus {
+
+Id MakeTransportId(ConnectionSpecificId connection_id,
+                   ConnectionSpecificId local_id) {
+  return (connection_id << 16) | local_id;
+}
+
+// Helper called to construct a local window object from transport data.
+Window* AddWindowToConnection(WindowTreeClientImpl* client,
+                              Window* parent,
+                              const mojo::ViewDataPtr& window_data) {
+  // We don't use the cto that takes a WindowTreeConnection here, since it will
+  // call back to the service and attempt to create a new view.
+  Window* window = WindowPrivate::LocalCreate();
+  WindowPrivate private_window(window);
+  private_window.set_connection(client);
+  private_window.set_id(window_data->view_id);
+  private_window.set_visible(window_data->visible);
+  private_window.set_drawn(window_data->drawn);
+  private_window.LocalSetViewportMetrics(mojo::ViewportMetrics(),
+                                         *window_data->viewport_metrics);
+  private_window.set_properties(
+      window_data->properties
+          .To<std::map<std::string, std::vector<uint8_t>>>());
+  client->AddWindow(window);
+  private_window.LocalSetBounds(mojo::Rect(), *window_data->bounds);
+  if (parent)
+    WindowPrivate(parent).LocalAddChild(window);
+  return window;
+}
+
+Window* BuildWindowTree(WindowTreeClientImpl* client,
+                        const mojo::Array<mojo::ViewDataPtr>& windows,
+                        Window* initial_parent) {
+  std::vector<Window*> parents;
+  Window* root = NULL;
+  Window* last_window = NULL;
+  if (initial_parent)
+    parents.push_back(initial_parent);
+  for (size_t i = 0; i < windows.size(); ++i) {
+    if (last_window && windows[i]->parent_id == last_window->id()) {
+      parents.push_back(last_window);
+    } else if (!parents.empty()) {
+      while (parents.back()->id() != windows[i]->parent_id)
+        parents.pop_back();
+    }
+    Window* window = AddWindowToConnection(
+        client, !parents.empty() ? parents.back() : NULL, windows[i]);
+    if (!last_window)
+      root = window;
+    last_window = window;
+  }
+  return root;
+}
+
+WindowTreeConnection* WindowTreeConnection::Create(
+    WindowTreeDelegate* delegate,
+    mojo::InterfaceRequest<mojo::ViewTreeClient> request,
+    CreateType create_type) {
+  WindowTreeClientImpl* client =
+      new WindowTreeClientImpl(delegate, request.Pass());
+  if (create_type == CreateType::WAIT_FOR_EMBED)
+    client->WaitForEmbed();
+  return client;
+}
+
+WindowTreeClientImpl::WindowTreeClientImpl(
+    WindowTreeDelegate* delegate,
+    mojo::InterfaceRequest<mojo::ViewTreeClient> request)
+    : connection_id_(0),
+      next_id_(1),
+      delegate_(delegate),
+      root_(nullptr),
+      capture_window_(nullptr),
+      focused_window_(nullptr),
+      activated_window_(nullptr),
+      binding_(this, request.Pass()),
+      is_embed_root_(false),
+      in_destructor_(false) {}
+
+WindowTreeClientImpl::~WindowTreeClientImpl() {
+  in_destructor_ = true;
+
+  std::vector<Window*> non_owned;
+  while (!windows_.empty()) {
+    IdToWindowMap::iterator it = windows_.begin();
+    if (OwnsWindow(it->second->id())) {
+      it->second->Destroy();
+    } else {
+      non_owned.push_back(it->second);
+      windows_.erase(it);
+    }
+  }
+
+  // Delete the non-owned views last. In the typical case these are roots. The
+  // exception is the window manager and embed roots, which may know about
+  // other random windows that it doesn't own.
+  // NOTE: we manually delete as we're a friend.
+  for (size_t i = 0; i < non_owned.size(); ++i)
+    delete non_owned[i];
+
+  delegate_->OnConnectionLost(this);
+}
+
+void WindowTreeClientImpl::WaitForEmbed() {
+  DCHECK(!root_);
+  // OnEmbed() is the first function called.
+  binding_.WaitForIncomingMethodCall();
+  // TODO(sky): deal with pipe being closed before we get OnEmbed().
+}
+
+void WindowTreeClientImpl::DestroyWindow(Id window_id) {
+  DCHECK(tree_);
+  tree_->DeleteView(window_id, ActionCompletedCallback());
+}
+
+void WindowTreeClientImpl::AddChild(Id child_id, Id parent_id) {
+  DCHECK(tree_);
+  tree_->AddView(parent_id, child_id, ActionCompletedCallback());
+}
+
+void WindowTreeClientImpl::RemoveChild(Id child_id, Id parent_id) {
+  DCHECK(tree_);
+  tree_->RemoveViewFromParent(child_id, ActionCompletedCallback());
+}
+
+void WindowTreeClientImpl::Reorder(Id window_id,
+                                   Id relative_window_id,
+                                   mojo::OrderDirection direction) {
+  DCHECK(tree_);
+  tree_->ReorderView(window_id, relative_window_id, direction,
+                     ActionCompletedCallback());
+}
+
+bool WindowTreeClientImpl::OwnsWindow(Id id) const {
+  return HiWord(id) == connection_id_;
+}
+
+void WindowTreeClientImpl::SetBounds(Id window_id, const mojo::Rect& bounds) {
+  DCHECK(tree_);
+  tree_->SetViewBounds(window_id, bounds.Clone(), ActionCompletedCallback());
+}
+
+void WindowTreeClientImpl::SetFocus(Id window_id) {
+  // In order for us to get here we had to have exposed a window, which implies
+  // we
+  // got a connection.
+  DCHECK(tree_);
+  tree_->SetFocus(window_id);
+}
+
+void WindowTreeClientImpl::SetVisible(Id window_id, bool visible) {
+  DCHECK(tree_);
+  tree_->SetViewVisibility(window_id, visible, ActionCompletedCallback());
+}
+
+void WindowTreeClientImpl::SetProperty(Id window_id,
+                                       const std::string& name,
+                                       const std::vector<uint8_t>& data) {
+  DCHECK(tree_);
+  tree_->SetViewProperty(window_id, mojo::String(name),
+                         mojo::Array<uint8_t>::From(data),
+                         ActionCompletedCallback());
+}
+
+void WindowTreeClientImpl::SetViewTextInputState(
+    Id window_id,
+    mojo::TextInputStatePtr state) {
+  DCHECK(tree_);
+  tree_->SetViewTextInputState(window_id, state.Pass());
+}
+
+void WindowTreeClientImpl::SetImeVisibility(Id window_id,
+                                            bool visible,
+                                            mojo::TextInputStatePtr state) {
+  DCHECK(tree_);
+  tree_->SetImeVisibility(window_id, visible, state.Pass());
+}
+
+void WindowTreeClientImpl::Embed(
+    Id window_id,
+    mojo::ViewTreeClientPtr client,
+    uint32_t policy_bitmask,
+    const mojo::ViewTree::EmbedCallback& callback) {
+  DCHECK(tree_);
+  tree_->Embed(window_id, client.Pass(), policy_bitmask, callback);
+}
+
+void WindowTreeClientImpl::RequestSurface(
+    Id window_id,
+    mojo::InterfaceRequest<mojo::Surface> surface,
+    mojo::SurfaceClientPtr client) {
+  DCHECK(tree_);
+  tree_->RequestSurface(window_id, surface.Pass(), client.Pass());
+}
+
+void WindowTreeClientImpl::AddWindow(Window* window) {
+  DCHECK(windows_.find(window->id()) == windows_.end());
+  windows_[window->id()] = window;
+}
+
+void WindowTreeClientImpl::RemoveWindow(Id window_id) {
+  if (focused_window_ && focused_window_->id() == window_id)
+    OnWindowFocused(0);
+
+  IdToWindowMap::iterator it = windows_.find(window_id);
+  if (it != windows_.end())
+    windows_.erase(it);
+}
+
+void WindowTreeClientImpl::OnRootDestroyed(Window* root) {
+  DCHECK_EQ(root, root_);
+  root_ = nullptr;
+
+  // When the root is gone we can't do anything useful.
+  if (!in_destructor_)
+    delete this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowTreeClientImpl, WindowTreeConnection implementation:
+
+Id WindowTreeClientImpl::CreateWindowOnServer() {
+  DCHECK(tree_);
+  const Id window_id = MakeTransportId(connection_id_, next_id_++);
+  tree_->CreateView(window_id, [this](mojo::ErrorCode code) {
+    OnActionCompleted(code == mojo::ERROR_CODE_NONE);
+  });
+  return window_id;
+}
+
+Window* WindowTreeClientImpl::GetRoot() {
+  return root_;
+}
+
+Window* WindowTreeClientImpl::GetWindowById(Id id) {
+  IdToWindowMap::const_iterator it = windows_.find(id);
+  return it != windows_.end() ? it->second : NULL;
+}
+
+Window* WindowTreeClientImpl::GetFocusedWindow() {
+  return focused_window_;
+}
+
+Window* WindowTreeClientImpl::CreateWindow() {
+  Window* window = new Window(this, CreateWindowOnServer());
+  AddWindow(window);
+  return window;
+}
+
+bool WindowTreeClientImpl::IsEmbedRoot() {
+  return is_embed_root_;
+}
+
+ConnectionSpecificId WindowTreeClientImpl::GetConnectionId() {
+  return connection_id_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowTreeClientImpl, ViewTreeClient implementation:
+
+void WindowTreeClientImpl::OnEmbed(ConnectionSpecificId connection_id,
+                                   mojo::ViewDataPtr root_data,
+                                   mojo::ViewTreePtr tree,
+                                   Id focused_window_id,
+                                   uint32 access_policy) {
+  if (tree) {
+    DCHECK(!tree_);
+    tree_ = tree.Pass();
+    tree_.set_connection_error_handler([this]() { delete this; });
+  }
+  connection_id_ = connection_id;
+  is_embed_root_ =
+      (access_policy & mojo::ViewTree::ACCESS_POLICY_EMBED_ROOT) != 0;
+
+  DCHECK(!root_);
+  root_ = AddWindowToConnection(this, nullptr, root_data);
+
+  focused_window_ = GetWindowById(focused_window_id);
+
+  delegate_->OnEmbed(root_);
+}
+
+void WindowTreeClientImpl::OnEmbeddedAppDisconnected(Id window_id) {
+  Window* window = GetWindowById(window_id);
+  if (window) {
+    FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window).observers(),
+                      OnWindowEmbeddedAppDisconnected(window));
+  }
+}
+
+void WindowTreeClientImpl::OnUnembed() {
+  delegate_->OnUnembed();
+  // This will send out the various notifications.
+  delete this;
+}
+
+void WindowTreeClientImpl::OnWindowBoundsChanged(Id window_id,
+                                                 mojo::RectPtr old_bounds,
+                                                 mojo::RectPtr new_bounds) {
+  Window* window = GetWindowById(window_id);
+  WindowPrivate(window).LocalSetBounds(*old_bounds, *new_bounds);
+}
+
+namespace {
+
+void SetViewportMetricsOnDecendants(Window* root,
+                                    const mojo::ViewportMetrics& old_metrics,
+                                    const mojo::ViewportMetrics& new_metrics) {
+  WindowPrivate(root).LocalSetViewportMetrics(old_metrics, new_metrics);
+  const Window::Children& children = root->children();
+  for (size_t i = 0; i < children.size(); ++i)
+    SetViewportMetricsOnDecendants(children[i], old_metrics, new_metrics);
+}
+}
+
+void WindowTreeClientImpl::OnWindowViewportMetricsChanged(
+    mojo::ViewportMetricsPtr old_metrics,
+    mojo::ViewportMetricsPtr new_metrics) {
+  Window* window = GetRoot();
+  if (window)
+    SetViewportMetricsOnDecendants(window, *old_metrics, *new_metrics);
+}
+
+void WindowTreeClientImpl::OnWindowHierarchyChanged(
+    Id window_id,
+    Id new_parent_id,
+    Id old_parent_id,
+    mojo::Array<mojo::ViewDataPtr> windows) {
+  Window* initial_parent =
+      windows.size() ? GetWindowById(windows[0]->parent_id) : NULL;
+
+  const bool was_window_known = GetWindowById(window_id) != nullptr;
+
+  BuildWindowTree(this, windows, initial_parent);
+
+  // If the window was not known, then BuildWindowTree() will have created it
+  // and
+  // parented the window.
+  if (!was_window_known)
+    return;
+
+  Window* new_parent = GetWindowById(new_parent_id);
+  Window* old_parent = GetWindowById(old_parent_id);
+  Window* window = GetWindowById(window_id);
+  if (new_parent)
+    WindowPrivate(new_parent).LocalAddChild(window);
+  else
+    WindowPrivate(old_parent).LocalRemoveChild(window);
+}
+
+void WindowTreeClientImpl::OnWindowReordered(Id window_id,
+                                             Id relative_window_id,
+                                             mojo::OrderDirection direction) {
+  Window* window = GetWindowById(window_id);
+  Window* relative_window = GetWindowById(relative_window_id);
+  if (window && relative_window)
+    WindowPrivate(window).LocalReorder(relative_window, direction);
+}
+
+void WindowTreeClientImpl::OnWindowDeleted(Id window_id) {
+  Window* window = GetWindowById(window_id);
+  if (window)
+    WindowPrivate(window).LocalDestroy();
+}
+
+void WindowTreeClientImpl::OnWindowVisibilityChanged(Id window_id,
+                                                     bool visible) {
+  // TODO(sky): there is a race condition here. If this client and another
+  // client change the visibility at the same time the wrong value may be set.
+  // Deal with this some how.
+  Window* window = GetWindowById(window_id);
+  if (window)
+    WindowPrivate(window).LocalSetVisible(visible);
+}
+
+void WindowTreeClientImpl::OnWindowDrawnStateChanged(Id window_id, bool drawn) {
+  Window* window = GetWindowById(window_id);
+  if (window)
+    WindowPrivate(window).LocalSetDrawn(drawn);
+}
+
+void WindowTreeClientImpl::OnWindowSharedPropertyChanged(
+    Id window_id,
+    const mojo::String& name,
+    mojo::Array<uint8_t> new_data) {
+  Window* window = GetWindowById(window_id);
+  if (window) {
+    std::vector<uint8_t> data;
+    std::vector<uint8_t>* data_ptr = NULL;
+    if (!new_data.is_null()) {
+      data = new_data.To<std::vector<uint8_t>>();
+      data_ptr = &data;
+    }
+
+    window->SetSharedProperty(name, data_ptr);
+  }
+}
+
+void WindowTreeClientImpl::OnWindowInputEvent(
+    Id window_id,
+    mojo::EventPtr event,
+    const mojo::Callback<void()>& ack_callback) {
+  Window* window = GetWindowById(window_id);
+  if (window) {
+    FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window).observers(),
+                      OnWindowInputEvent(window, event));
+  }
+  ack_callback.Run();
+}
+
+void WindowTreeClientImpl::OnWindowFocused(Id focused_window_id) {
+  Window* focused = GetWindowById(focused_window_id);
+  Window* blurred = focused_window_;
+  // Update |focused_window_| before calling any of the observers, so that the
+  // observers get the correct result from calling |Window::HasFocus()|,
+  // |WindowTreeConnection::GetFocusedWindow()| etc.
+  focused_window_ = focused;
+  if (blurred) {
+    FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(blurred).observers(),
+                      OnWindowFocusChanged(focused, blurred));
+  }
+  if (focused) {
+    FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(focused).observers(),
+                      OnWindowFocusChanged(focused, blurred));
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowTreeClientImpl, private:
+
+void WindowTreeClientImpl::OnActionCompleted(bool success) {
+  if (!change_acked_callback_.is_null())
+    change_acked_callback_.Run();
+}
+
+mojo::Callback<void(bool)> WindowTreeClientImpl::ActionCompletedCallback() {
+  return [this](bool success) { OnActionCompleted(success); };
+}
+
+}  // namespace mus
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.h b/components/mus/public/cpp/lib/window_tree_client_impl.h
new file mode 100644
index 0000000..7f3a7ba
--- /dev/null
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.h
@@ -0,0 +1,166 @@
+// 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 COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_TREE_CLIENT_IMPL_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_TREE_CLIENT_IMPL_H_
+
+#include "components/mus/public/cpp/types.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/interfaces/view_tree.mojom.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
+
+namespace mus {
+class WindowTreeConnection;
+class WindowTreeDelegate;
+
+// Manages the connection with the Window Server service.
+class WindowTreeClientImpl : public WindowTreeConnection,
+                             public mojo::ViewTreeClient {
+ public:
+  WindowTreeClientImpl(WindowTreeDelegate* delegate,
+                       mojo::InterfaceRequest<mojo::ViewTreeClient> request);
+  ~WindowTreeClientImpl() override;
+
+  // Wait for OnEmbed(), returning when done.
+  void WaitForEmbed();
+
+  bool connected() const { return tree_; }
+  ConnectionSpecificId connection_id() const { return connection_id_; }
+
+  // API exposed to the window implementations that pushes local changes to the
+  // service.
+  void DestroyWindow(Id window_id);
+
+  // These methods take TransportIds. For windows owned by the current
+  // connection,
+  // the connection id high word can be zero. In all cases, the TransportId 0x1
+  // refers to the root window.
+  void AddChild(Id child_id, Id parent_id);
+  void RemoveChild(Id child_id, Id parent_id);
+
+  void Reorder(Id window_id,
+               Id relative_window_id,
+               mojo::OrderDirection direction);
+
+  // Returns true if the specified window was created by this connection.
+  bool OwnsWindow(Id id) const;
+
+  void SetBounds(Id window_id, const mojo::Rect& bounds);
+  void SetFocus(Id window_id);
+  void SetVisible(Id window_id, bool visible);
+  void SetProperty(Id window_id,
+                   const std::string& name,
+                   const std::vector<uint8_t>& data);
+  void SetViewTextInputState(Id window_id, mojo::TextInputStatePtr state);
+  void SetImeVisibility(Id window_id,
+                        bool visible,
+                        mojo::TextInputStatePtr state);
+
+  void Embed(Id window_id,
+             mojo::ViewTreeClientPtr client,
+             uint32_t policy_bitmask,
+             const mojo::ViewTree::EmbedCallback& callback);
+
+  void RequestSurface(Id window_id,
+                      mojo::InterfaceRequest<mojo::Surface> surface,
+                      mojo::SurfaceClientPtr client);
+
+  void set_change_acked_callback(const mojo::Callback<void(void)>& callback) {
+    change_acked_callback_ = callback;
+  }
+  void ClearChangeAckedCallback() { change_acked_callback_.reset(); }
+
+  // Start/stop tracking views. While tracked, they can be retrieved via
+  // WindowTreeConnection::GetWindowById.
+  void AddWindow(Window* window);
+  void RemoveWindow(Id window_id);
+
+  bool is_embed_root() const { return is_embed_root_; }
+
+  // Called after the root window's observers have been notified of destruction
+  // (as the last step of ~Window). This ordering ensures that the Window Server
+  // is torn down after the root.
+  void OnRootDestroyed(Window* root);
+
+ private:
+  typedef std::map<Id, Window*> IdToWindowMap;
+
+  Id CreateWindowOnServer();
+
+  // Overridden from WindowTreeConnection:
+  Window* GetRoot() override;
+  Window* GetWindowById(Id id) override;
+  Window* GetFocusedWindow() override;
+  Window* CreateWindow() override;
+  bool IsEmbedRoot() override;
+  ConnectionSpecificId GetConnectionId() override;
+
+  // Overridden from ViewTreeClient:
+  void OnEmbed(ConnectionSpecificId connection_id,
+               mojo::ViewDataPtr root,
+               mojo::ViewTreePtr tree,
+               Id focused_window_id,
+               uint32_t access_policy) override;
+  void OnEmbeddedAppDisconnected(Id window_id) override;
+  void OnUnembed() override;
+  void OnWindowBoundsChanged(Id window_id,
+                             mojo::RectPtr old_bounds,
+                             mojo::RectPtr new_bounds) override;
+  void OnWindowViewportMetricsChanged(
+      mojo::ViewportMetricsPtr old_metrics,
+      mojo::ViewportMetricsPtr new_metrics) override;
+  void OnWindowHierarchyChanged(
+      Id window_id,
+      Id new_parent_id,
+      Id old_parent_id,
+      mojo::Array<mojo::ViewDataPtr> windows) override;
+  void OnWindowReordered(Id window_id,
+                         Id relative_window_id,
+                         mojo::OrderDirection direction) override;
+  void OnWindowDeleted(Id window_id) override;
+  void OnWindowVisibilityChanged(Id window_id, bool visible) override;
+  void OnWindowDrawnStateChanged(Id window_id, bool drawn) override;
+  void OnWindowSharedPropertyChanged(Id window_id,
+                                     const mojo::String& name,
+                                     mojo::Array<uint8_t> new_data) override;
+  void OnWindowInputEvent(Id window_id,
+                          mojo::EventPtr event,
+                          const mojo::Callback<void()>& callback) override;
+  void OnWindowFocused(Id focused_window_id) override;
+
+  void RootDestroyed(Window* root);
+
+  void OnActionCompleted(bool success);
+
+  mojo::Callback<void(bool)> ActionCompletedCallback();
+
+  ConnectionSpecificId connection_id_;
+  ConnectionSpecificId next_id_;
+
+  mojo::Callback<void(void)> change_acked_callback_;
+
+  WindowTreeDelegate* delegate_;
+
+  Window* root_;
+
+  IdToWindowMap windows_;
+
+  Window* capture_window_;
+  Window* focused_window_;
+  Window* activated_window_;
+
+  mojo::Binding<ViewTreeClient> binding_;
+  mojo::ViewTreePtr tree_;
+
+  bool is_embed_root_;
+
+  bool in_destructor_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(WindowTreeClientImpl);
+};
+
+}  // namespace mus
+
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_TREE_CLIENT_IMPL_H_
diff --git a/components/mus/public/cpp/lib/view_tree_delegate.cc b/components/mus/public/cpp/lib/window_tree_delegate.cc
similarity index 67%
rename from components/mus/public/cpp/lib/view_tree_delegate.cc
rename to components/mus/public/cpp/lib/window_tree_delegate.cc
index c1344146..c9377ba 100644
--- a/components/mus/public/cpp/lib/view_tree_delegate.cc
+++ b/components/mus/public/cpp/lib/window_tree_delegate.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/mus/public/cpp/view_tree_delegate.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
 
 namespace mus {
 
-void ViewTreeDelegate::OnUnembed() {}
+void WindowTreeDelegate::OnUnembed() {}
 
 }  // namespace mus
diff --git a/components/mus/public/cpp/lib/window_tree_host_factory.cc b/components/mus/public/cpp/lib/window_tree_host_factory.cc
new file mode 100644
index 0000000..0636559
--- /dev/null
+++ b/components/mus/public/cpp/lib/window_tree_host_factory.cc
@@ -0,0 +1,36 @@
+// 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 "components/mus/public/cpp/window_tree_host_factory.h"
+
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
+#include "mojo/application/public/cpp/application_impl.h"
+
+namespace mus {
+
+void CreateWindowTreeHost(mojo::ViewTreeHostFactory* factory,
+                          mojo::ViewTreeHostClientPtr host_client,
+                          WindowTreeDelegate* delegate,
+                          mojo::ViewTreeHostPtr* host) {
+  mojo::ViewTreeClientPtr tree_client;
+  WindowTreeConnection::Create(
+      delegate, GetProxy(&tree_client),
+      WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
+  factory->CreateWindowTreeHost(GetProxy(host), host_client.Pass(),
+                                tree_client.Pass());
+}
+
+void CreateSingleWindowTreeHost(mojo::ApplicationImpl* app,
+                                WindowTreeDelegate* delegate,
+                                mojo::ViewTreeHostPtr* host) {
+  mojo::ViewTreeHostFactoryPtr factory;
+  mojo::URLRequestPtr request(mojo::URLRequest::New());
+  request->url = "mojo:mus";
+  app->ConnectToService(request.Pass(), &factory);
+  CreateWindowTreeHost(factory.get(), mojo::ViewTreeHostClientPtr(), delegate,
+                       host);
+}
+
+}  // namespace mus
diff --git a/components/mus/public/cpp/output_surface.h b/components/mus/public/cpp/output_surface.h
index e187fb3b..f99665d 100644
--- a/components/mus/public/cpp/output_surface.h
+++ b/components/mus/public/cpp/output_surface.h
@@ -8,16 +8,16 @@
 #include "base/macros.h"
 #include "cc/output/output_surface.h"
 #include "cc/surfaces/surface_id.h"
-#include "components/mus/public/cpp/view_surface.h"
-#include "components/mus/public/cpp/view_surface_client.h"
+#include "components/mus/public/cpp/window_surface.h"
+#include "components/mus/public/cpp/window_surface_client.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
 
 namespace mus {
 
-class OutputSurface : public cc::OutputSurface, public ViewSurfaceClient {
+class OutputSurface : public cc::OutputSurface, public WindowSurfaceClient {
  public:
   OutputSurface(const scoped_refptr<cc::ContextProvider>& context_provider,
-                scoped_ptr<ViewSurface> surface);
+                scoped_ptr<WindowSurface> surface);
   ~OutputSurface() override;
 
   // cc::OutputSurface implementation.
@@ -26,14 +26,14 @@
   void DetachFromClient() override;
 
  private:
-  // ViewSurfaceClient implementation:
+  // WindowSurfaceClient implementation:
   void OnResourcesReturned(
-      ViewSurface* surface,
+      WindowSurface* surface,
       mojo::Array<mojo::ReturnedResourcePtr> resources) override;
 
   void SwapBuffersComplete();
 
-  scoped_ptr<ViewSurface> surface_;
+  scoped_ptr<WindowSurface> surface_;
 
   DISALLOW_COPY_AND_ASSIGN(OutputSurface);
 };
diff --git a/components/mus/public/cpp/scoped_view_ptr.h b/components/mus/public/cpp/scoped_view_ptr.h
deleted file mode 100644
index 92c12f2..0000000
--- a/components/mus/public/cpp/scoped_view_ptr.h
+++ /dev/null
@@ -1,38 +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 COMPONENTS_MUS_PUBLIC_CPP_SCOPED_VIEW_PTR_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_SCOPED_VIEW_PTR_H_
-
-#include "components/mus/public/cpp/view_observer.h"
-
-namespace mus {
-
-// Wraps a View, taking overship of the View. Also deals with View being
-// destroyed while ScopedViewPtr still exists.
-class ScopedViewPtr : public ViewObserver {
- public:
-  explicit ScopedViewPtr(View* view);
-  ~ScopedViewPtr() override;
-
-  // Destroys |view|. If |view| is the root of the ViewManager than the
-  // ViewManager is destroyed (which in turn destroys |view|).
-  static void DeleteViewOrViewManager(View* view);
-
-  View* view() { return view_; }
-  const View* view() const { return view_; }
-
- private:
-  void DetachFromView();
-
-  void OnViewDestroying(View* view) override;
-
-  View* view_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedViewPtr);
-};
-
-}  // namespace mus
-
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_SCOPED_VIEW_PTR_H_
diff --git a/components/mus/public/cpp/scoped_window_ptr.h b/components/mus/public/cpp/scoped_window_ptr.h
new file mode 100644
index 0000000..9fb7ada
--- /dev/null
+++ b/components/mus/public/cpp/scoped_window_ptr.h
@@ -0,0 +1,38 @@
+// 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 COMPONENTS_MUS_PUBLIC_CPP_SCOPED_WINDOW_PTR_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_SCOPED_WINDOW_PTR_H_
+
+#include "components/mus/public/cpp/window_observer.h"
+
+namespace mus {
+
+// Wraps a View, taking overship of the View. Also deals with View being
+// destroyed while ScopedWindowPtr still exists.
+class ScopedWindowPtr : public WindowObserver {
+ public:
+  explicit ScopedWindowPtr(Window* view);
+  ~ScopedWindowPtr() override;
+
+  // Destroys |window|. If |window| is the root of the WindowManager than the
+  // WindowManager is destroyed (which in turn destroys |window|).
+  static void DeleteWindowOrWindowManager(Window* window);
+
+  Window* window() { return window_; }
+  const Window* window() const { return window_; }
+
+ private:
+  void DetachFromWindow();
+
+  void OnWindowDestroying(Window* window) override;
+
+  Window* window_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedWindowPtr);
+};
+
+}  // namespace mus
+
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_SCOPED_WINDOW_PTR_H_
diff --git a/components/mus/public/cpp/tests/BUILD.gn b/components/mus/public/cpp/tests/BUILD.gn
index c5829949..b9ba5d0 100644
--- a/components/mus/public/cpp/tests/BUILD.gn
+++ b/components/mus/public/cpp/tests/BUILD.gn
@@ -9,8 +9,8 @@
   testonly = true
 
   sources = [
-    "view_manager_test_base.cc",
-    "view_manager_test_base.h",
+    "window_server_test_base.cc",
+    "window_server_test_base.h",
   ]
 
   deps = [
@@ -26,9 +26,9 @@
 test("mojo_view_manager_lib_unittests") {
   sources = [
     "run_all_unittests.cc",
-    "view_manager_test_suite.cc",
-    "view_manager_test_suite.h",
-    "view_unittest.cc",
+    "window_server_test_suite.cc",
+    "window_server_test_suite.h",
+    "window_unittest.cc",
   ]
 
   deps = [
diff --git a/components/mus/public/cpp/tests/run_all_unittests.cc b/components/mus/public/cpp/tests/run_all_unittests.cc
index ee82a07..1af6dbd2 100644
--- a/components/mus/public/cpp/tests/run_all_unittests.cc
+++ b/components/mus/public/cpp/tests/run_all_unittests.cc
@@ -4,12 +4,12 @@
 
 #include "base/bind.h"
 #include "base/test/launcher/unit_test_launcher.h"
-#include "components/mus/public/cpp/tests/view_manager_test_suite.h"
+#include "components/mus/public/cpp/tests/window_server_test_suite.h"
 
 int main(int argc, char** argv) {
-  mus::ViewManagerTestSuite test_suite(argc, argv);
+  mus::WindowServerTestSuite test_suite(argc, argv);
 
   return base::LaunchUnitTests(argc, argv,
-                               base::Bind(&mus::ViewManagerTestSuite::Run,
+                               base::Bind(&mus::WindowServerTestSuite::Run,
                                           base::Unretained(&test_suite)));
 }
diff --git a/components/mus/public/cpp/tests/view_manager_test_suite.h b/components/mus/public/cpp/tests/view_manager_test_suite.h
deleted file mode 100644
index b68bb2f3..0000000
--- a/components/mus/public/cpp/tests/view_manager_test_suite.h
+++ /dev/null
@@ -1,27 +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 COMPONENTS_MUS_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_SUITE_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_SUITE_H_
-
-#include "base/test/test_suite.h"
-#include "third_party/mojo/src/mojo/public/cpp/system/macros.h"
-
-namespace mus {
-
-class ViewManagerTestSuite : public base::TestSuite {
- public:
-  ViewManagerTestSuite(int argc, char** argv);
-  ~ViewManagerTestSuite() override;
-
- protected:
-  void Initialize() override;
-
- private:
-  MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerTestSuite);
-};
-
-}  // namespace mus
-
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_SUITE_H_
diff --git a/components/mus/public/cpp/tests/view_unittest.cc b/components/mus/public/cpp/tests/view_unittest.cc
deleted file mode 100644
index c991ca3..0000000
--- a/components/mus/public/cpp/tests/view_unittest.cc
+++ /dev/null
@@ -1,874 +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 "components/mus/public/cpp/view.h"
-
-#include "base/logging.h"
-#include "base/strings/stringprintf.h"
-#include "components/mus/public/cpp/lib/view_private.h"
-#include "components/mus/public/cpp/util.h"
-#include "components/mus/public/cpp/view_observer.h"
-#include "components/mus/public/cpp/view_property.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mus {
-
-// View ------------------------------------------------------------------------
-
-typedef testing::Test ViewTest;
-
-// Subclass with public ctor/dtor.
-class TestView : public View {
- public:
-  TestView() { ViewPrivate(this).set_id(1); }
-  ~TestView() {}
-
- private:
-  MOJO_DISALLOW_COPY_AND_ASSIGN(TestView);
-};
-
-TEST_F(ViewTest, AddChild) {
-  TestView v1;
-  TestView v11;
-  v1.AddChild(&v11);
-  EXPECT_EQ(1U, v1.children().size());
-}
-
-TEST_F(ViewTest, RemoveChild) {
-  TestView v1;
-  TestView v11;
-  v1.AddChild(&v11);
-  EXPECT_EQ(1U, v1.children().size());
-  v1.RemoveChild(&v11);
-  EXPECT_EQ(0U, v1.children().size());
-}
-
-TEST_F(ViewTest, Reparent) {
-  TestView v1;
-  TestView v2;
-  TestView v11;
-  v1.AddChild(&v11);
-  EXPECT_EQ(1U, v1.children().size());
-  v2.AddChild(&v11);
-  EXPECT_EQ(1U, v2.children().size());
-  EXPECT_EQ(0U, v1.children().size());
-}
-
-TEST_F(ViewTest, Contains) {
-  TestView v1;
-
-  // Direct descendant.
-  TestView v11;
-  v1.AddChild(&v11);
-  EXPECT_TRUE(v1.Contains(&v11));
-
-  // Indirect descendant.
-  TestView v111;
-  v11.AddChild(&v111);
-  EXPECT_TRUE(v1.Contains(&v111));
-}
-
-TEST_F(ViewTest, GetChildById) {
-  TestView v1;
-  ViewPrivate(&v1).set_id(1);
-  TestView v11;
-  ViewPrivate(&v11).set_id(11);
-  v1.AddChild(&v11);
-  TestView v111;
-  ViewPrivate(&v111).set_id(111);
-  v11.AddChild(&v111);
-
-  // Find direct & indirect descendents.
-  EXPECT_EQ(&v11, v1.GetChildById(v11.id()));
-  EXPECT_EQ(&v111, v1.GetChildById(v111.id()));
-}
-
-TEST_F(ViewTest, DrawnAndVisible) {
-  TestView v1;
-  EXPECT_TRUE(v1.visible());
-  EXPECT_FALSE(v1.IsDrawn());
-
-  ViewPrivate(&v1).set_drawn(true);
-
-  TestView v11;
-  v1.AddChild(&v11);
-  EXPECT_TRUE(v11.visible());
-  EXPECT_TRUE(v11.IsDrawn());
-
-  v1.RemoveChild(&v11);
-  EXPECT_TRUE(v11.visible());
-  EXPECT_FALSE(v11.IsDrawn());
-}
-
-namespace {
-DEFINE_VIEW_PROPERTY_KEY(int, kIntKey, -2);
-DEFINE_VIEW_PROPERTY_KEY(const char*, kStringKey, "squeamish");
-}
-
-TEST_F(ViewTest, Property) {
-  TestView v;
-
-  // Non-existent properties should return the default values.
-  EXPECT_EQ(-2, v.GetLocalProperty(kIntKey));
-  EXPECT_EQ(std::string("squeamish"), v.GetLocalProperty(kStringKey));
-
-  // A set property value should be returned again (even if it's the default
-  // value).
-  v.SetLocalProperty(kIntKey, INT_MAX);
-  EXPECT_EQ(INT_MAX, v.GetLocalProperty(kIntKey));
-  v.SetLocalProperty(kIntKey, -2);
-  EXPECT_EQ(-2, v.GetLocalProperty(kIntKey));
-  v.SetLocalProperty(kIntKey, INT_MIN);
-  EXPECT_EQ(INT_MIN, v.GetLocalProperty(kIntKey));
-
-  v.SetLocalProperty(kStringKey, static_cast<const char*>(NULL));
-  EXPECT_EQ(NULL, v.GetLocalProperty(kStringKey));
-  v.SetLocalProperty(kStringKey, "squeamish");
-  EXPECT_EQ(std::string("squeamish"), v.GetLocalProperty(kStringKey));
-  v.SetLocalProperty(kStringKey, "ossifrage");
-  EXPECT_EQ(std::string("ossifrage"), v.GetLocalProperty(kStringKey));
-
-  // ClearProperty should restore the default value.
-  v.ClearLocalProperty(kIntKey);
-  EXPECT_EQ(-2, v.GetLocalProperty(kIntKey));
-  v.ClearLocalProperty(kStringKey);
-  EXPECT_EQ(std::string("squeamish"), v.GetLocalProperty(kStringKey));
-}
-
-namespace {
-
-class TestProperty {
- public:
-  TestProperty() {}
-  virtual ~TestProperty() { last_deleted_ = this; }
-  static TestProperty* last_deleted() { return last_deleted_; }
-
- private:
-  static TestProperty* last_deleted_;
-  MOJO_DISALLOW_COPY_AND_ASSIGN(TestProperty);
-};
-
-TestProperty* TestProperty::last_deleted_ = NULL;
-
-DEFINE_OWNED_VIEW_PROPERTY_KEY(TestProperty, kOwnedKey, NULL);
-
-}  // namespace
-
-TEST_F(ViewTest, OwnedProperty) {
-  TestProperty* p3 = NULL;
-  {
-    TestView v;
-    EXPECT_EQ(NULL, v.GetLocalProperty(kOwnedKey));
-    TestProperty* p1 = new TestProperty();
-    v.SetLocalProperty(kOwnedKey, p1);
-    EXPECT_EQ(p1, v.GetLocalProperty(kOwnedKey));
-    EXPECT_EQ(NULL, TestProperty::last_deleted());
-
-    TestProperty* p2 = new TestProperty();
-    v.SetLocalProperty(kOwnedKey, p2);
-    EXPECT_EQ(p2, v.GetLocalProperty(kOwnedKey));
-    EXPECT_EQ(p1, TestProperty::last_deleted());
-
-    v.ClearLocalProperty(kOwnedKey);
-    EXPECT_EQ(NULL, v.GetLocalProperty(kOwnedKey));
-    EXPECT_EQ(p2, TestProperty::last_deleted());
-
-    p3 = new TestProperty();
-    v.SetLocalProperty(kOwnedKey, p3);
-    EXPECT_EQ(p3, v.GetLocalProperty(kOwnedKey));
-    EXPECT_EQ(p2, TestProperty::last_deleted());
-  }
-
-  EXPECT_EQ(p3, TestProperty::last_deleted());
-}
-
-// ViewObserver --------------------------------------------------------
-
-typedef testing::Test ViewObserverTest;
-
-bool TreeChangeParamsMatch(const ViewObserver::TreeChangeParams& lhs,
-                           const ViewObserver::TreeChangeParams& rhs) {
-  return lhs.target == rhs.target && lhs.old_parent == rhs.old_parent &&
-         lhs.new_parent == rhs.new_parent && lhs.receiver == rhs.receiver;
-}
-
-class TreeChangeObserver : public ViewObserver {
- public:
-  explicit TreeChangeObserver(View* observee) : observee_(observee) {
-    observee_->AddObserver(this);
-  }
-  ~TreeChangeObserver() override { observee_->RemoveObserver(this); }
-
-  void Reset() { received_params_.clear(); }
-
-  const std::vector<TreeChangeParams>& received_params() {
-    return received_params_;
-  }
-
- private:
-  // Overridden from ViewObserver:
-  void OnTreeChanging(const TreeChangeParams& params) override {
-    received_params_.push_back(params);
-  }
-  void OnTreeChanged(const TreeChangeParams& params) override {
-    received_params_.push_back(params);
-  }
-
-  View* observee_;
-  std::vector<TreeChangeParams> received_params_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(TreeChangeObserver);
-};
-
-// Adds/Removes v11 to v1.
-TEST_F(ViewObserverTest, TreeChange_SimpleAddRemove) {
-  TestView v1;
-  TreeChangeObserver o1(&v1);
-  EXPECT_TRUE(o1.received_params().empty());
-
-  TestView v11;
-  TreeChangeObserver o11(&v11);
-  EXPECT_TRUE(o11.received_params().empty());
-
-  // Add.
-
-  v1.AddChild(&v11);
-
-  EXPECT_EQ(2U, o1.received_params().size());
-  ViewObserver::TreeChangeParams p1;
-  p1.target = &v11;
-  p1.receiver = &v1;
-  p1.old_parent = NULL;
-  p1.new_parent = &v1;
-  EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back()));
-
-  EXPECT_EQ(2U, o11.received_params().size());
-  ViewObserver::TreeChangeParams p11 = p1;
-  p11.receiver = &v11;
-  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front()));
-  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back()));
-
-  o1.Reset();
-  o11.Reset();
-  EXPECT_TRUE(o1.received_params().empty());
-  EXPECT_TRUE(o11.received_params().empty());
-
-  // Remove.
-
-  v1.RemoveChild(&v11);
-
-  EXPECT_EQ(2U, o1.received_params().size());
-  p1.target = &v11;
-  p1.receiver = &v1;
-  p1.old_parent = &v1;
-  p1.new_parent = NULL;
-  EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front()));
-
-  EXPECT_EQ(2U, o11.received_params().size());
-  p11 = p1;
-  p11.receiver = &v11;
-  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front()));
-  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back()));
-}
-
-// Creates these two trees:
-// v1
-//  +- v11
-// v111
-//  +- v1111
-//  +- v1112
-// Then adds/removes v111 from v11.
-TEST_F(ViewObserverTest, TreeChange_NestedAddRemove) {
-  TestView v1, v11, v111, v1111, v1112;
-
-  // Root tree.
-  v1.AddChild(&v11);
-
-  // Tree to be attached.
-  v111.AddChild(&v1111);
-  v111.AddChild(&v1112);
-
-  TreeChangeObserver o1(&v1), o11(&v11), o111(&v111), o1111(&v1111),
-      o1112(&v1112);
-  ViewObserver::TreeChangeParams p1, p11, p111, p1111, p1112;
-
-  // Add.
-
-  v11.AddChild(&v111);
-
-  EXPECT_EQ(2U, o1.received_params().size());
-  p1.target = &v111;
-  p1.receiver = &v1;
-  p1.old_parent = NULL;
-  p1.new_parent = &v11;
-  EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back()));
-
-  EXPECT_EQ(2U, o11.received_params().size());
-  p11 = p1;
-  p11.receiver = &v11;
-  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back()));
-
-  EXPECT_EQ(2U, o111.received_params().size());
-  p111 = p11;
-  p111.receiver = &v111;
-  EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front()));
-  EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back()));
-
-  EXPECT_EQ(2U, o1111.received_params().size());
-  p1111 = p111;
-  p1111.receiver = &v1111;
-  EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().front()));
-  EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().back()));
-
-  EXPECT_EQ(2U, o1112.received_params().size());
-  p1112 = p111;
-  p1112.receiver = &v1112;
-  EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().front()));
-  EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().back()));
-
-  // Remove.
-  o1.Reset();
-  o11.Reset();
-  o111.Reset();
-  o1111.Reset();
-  o1112.Reset();
-  EXPECT_TRUE(o1.received_params().empty());
-  EXPECT_TRUE(o11.received_params().empty());
-  EXPECT_TRUE(o111.received_params().empty());
-  EXPECT_TRUE(o1111.received_params().empty());
-  EXPECT_TRUE(o1112.received_params().empty());
-
-  v11.RemoveChild(&v111);
-
-  EXPECT_EQ(2U, o1.received_params().size());
-  p1.target = &v111;
-  p1.receiver = &v1;
-  p1.old_parent = &v11;
-  p1.new_parent = NULL;
-  EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front()));
-
-  EXPECT_EQ(2U, o11.received_params().size());
-  p11 = p1;
-  p11.receiver = &v11;
-  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front()));
-
-  EXPECT_EQ(2U, o111.received_params().size());
-  p111 = p11;
-  p111.receiver = &v111;
-  EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front()));
-  EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back()));
-
-  EXPECT_EQ(2U, o1111.received_params().size());
-  p1111 = p111;
-  p1111.receiver = &v1111;
-  EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().front()));
-  EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().back()));
-
-  EXPECT_EQ(2U, o1112.received_params().size());
-  p1112 = p111;
-  p1112.receiver = &v1112;
-  EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().front()));
-  EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().back()));
-}
-
-TEST_F(ViewObserverTest, TreeChange_Reparent) {
-  TestView v1, v11, v12, v111;
-  v1.AddChild(&v11);
-  v1.AddChild(&v12);
-  v11.AddChild(&v111);
-
-  TreeChangeObserver o1(&v1), o11(&v11), o12(&v12), o111(&v111);
-
-  // Reparent.
-  v12.AddChild(&v111);
-
-  // v1 (root) should see both changing and changed notifications.
-  EXPECT_EQ(4U, o1.received_params().size());
-  ViewObserver::TreeChangeParams p1;
-  p1.target = &v111;
-  p1.receiver = &v1;
-  p1.old_parent = &v11;
-  p1.new_parent = &v12;
-  EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front()));
-  EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back()));
-
-  // v11 should see changing notifications.
-  EXPECT_EQ(2U, o11.received_params().size());
-  ViewObserver::TreeChangeParams p11;
-  p11 = p1;
-  p11.receiver = &v11;
-  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front()));
-
-  // v12 should see changed notifications.
-  EXPECT_EQ(2U, o12.received_params().size());
-  ViewObserver::TreeChangeParams p12;
-  p12 = p1;
-  p12.receiver = &v12;
-  EXPECT_TRUE(TreeChangeParamsMatch(p12, o12.received_params().back()));
-
-  // v111 should see both changing and changed notifications.
-  EXPECT_EQ(2U, o111.received_params().size());
-  ViewObserver::TreeChangeParams p111;
-  p111 = p1;
-  p111.receiver = &v111;
-  EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front()));
-  EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back()));
-}
-
-namespace {
-
-class OrderChangeObserver : public ViewObserver {
- public:
-  struct Change {
-    View* view;
-    View* relative_view;
-    mojo::OrderDirection direction;
-  };
-  typedef std::vector<Change> Changes;
-
-  explicit OrderChangeObserver(View* observee) : observee_(observee) {
-    observee_->AddObserver(this);
-  }
-  ~OrderChangeObserver() override { observee_->RemoveObserver(this); }
-
-  Changes GetAndClearChanges() {
-    Changes changes;
-    changes_.swap(changes);
-    return changes;
-  }
-
- private:
-  // Overridden from ViewObserver:
-  void OnViewReordering(View* view,
-                        View* relative_view,
-                        mojo::OrderDirection direction) override {
-    OnViewReordered(view, relative_view, direction);
-  }
-
-  void OnViewReordered(View* view,
-                       View* relative_view,
-                       mojo::OrderDirection direction) override {
-    Change change;
-    change.view = view;
-    change.relative_view = relative_view;
-    change.direction = direction;
-    changes_.push_back(change);
-  }
-
-  View* observee_;
-  Changes changes_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver);
-};
-
-}  // namespace
-
-TEST_F(ViewObserverTest, Order) {
-  TestView v1, v11, v12, v13;
-  v1.AddChild(&v11);
-  v1.AddChild(&v12);
-  v1.AddChild(&v13);
-
-  // Order: v11, v12, v13
-  EXPECT_EQ(3U, v1.children().size());
-  EXPECT_EQ(&v11, v1.children().front());
-  EXPECT_EQ(&v13, v1.children().back());
-
-  {
-    OrderChangeObserver observer(&v11);
-
-    // Move v11 to front.
-    // Resulting order: v12, v13, v11
-    v11.MoveToFront();
-    EXPECT_EQ(&v12, v1.children().front());
-    EXPECT_EQ(&v11, v1.children().back());
-
-    OrderChangeObserver::Changes changes = observer.GetAndClearChanges();
-    ASSERT_EQ(2U, changes.size());
-    EXPECT_EQ(&v11, changes[0].view);
-    EXPECT_EQ(&v13, changes[0].relative_view);
-    EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[0].direction);
-
-    EXPECT_EQ(&v11, changes[1].view);
-    EXPECT_EQ(&v13, changes[1].relative_view);
-    EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[1].direction);
-  }
-
-  {
-    OrderChangeObserver observer(&v11);
-
-    // Move v11 to back.
-    // Resulting order: v11, v12, v13
-    v11.MoveToBack();
-    EXPECT_EQ(&v11, v1.children().front());
-    EXPECT_EQ(&v13, v1.children().back());
-
-    OrderChangeObserver::Changes changes = observer.GetAndClearChanges();
-    ASSERT_EQ(2U, changes.size());
-    EXPECT_EQ(&v11, changes[0].view);
-    EXPECT_EQ(&v12, changes[0].relative_view);
-    EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[0].direction);
-
-    EXPECT_EQ(&v11, changes[1].view);
-    EXPECT_EQ(&v12, changes[1].relative_view);
-    EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[1].direction);
-  }
-
-  {
-    OrderChangeObserver observer(&v11);
-
-    // Move v11 above v12.
-    // Resulting order: v12. v11, v13
-    v11.Reorder(&v12, mojo::ORDER_DIRECTION_ABOVE);
-    EXPECT_EQ(&v12, v1.children().front());
-    EXPECT_EQ(&v13, v1.children().back());
-
-    OrderChangeObserver::Changes changes = observer.GetAndClearChanges();
-    ASSERT_EQ(2U, changes.size());
-    EXPECT_EQ(&v11, changes[0].view);
-    EXPECT_EQ(&v12, changes[0].relative_view);
-    EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[0].direction);
-
-    EXPECT_EQ(&v11, changes[1].view);
-    EXPECT_EQ(&v12, changes[1].relative_view);
-    EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[1].direction);
-  }
-
-  {
-    OrderChangeObserver observer(&v11);
-
-    // Move v11 below v12.
-    // Resulting order: v11, v12, v13
-    v11.Reorder(&v12, mojo::ORDER_DIRECTION_BELOW);
-    EXPECT_EQ(&v11, v1.children().front());
-    EXPECT_EQ(&v13, v1.children().back());
-
-    OrderChangeObserver::Changes changes = observer.GetAndClearChanges();
-    ASSERT_EQ(2U, changes.size());
-    EXPECT_EQ(&v11, changes[0].view);
-    EXPECT_EQ(&v12, changes[0].relative_view);
-    EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[0].direction);
-
-    EXPECT_EQ(&v11, changes[1].view);
-    EXPECT_EQ(&v12, changes[1].relative_view);
-    EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[1].direction);
-  }
-}
-
-namespace {
-
-typedef std::vector<std::string> Changes;
-
-std::string ViewIdToString(Id id) {
-  return (id == 0) ? "null"
-                   : base::StringPrintf("%d,%d", HiWord(id), LoWord(id));
-}
-
-std::string RectToString(const mojo::Rect& rect) {
-  return base::StringPrintf("%d,%d %dx%d", rect.x, rect.y, rect.width,
-                            rect.height);
-}
-
-class BoundsChangeObserver : public ViewObserver {
- public:
-  explicit BoundsChangeObserver(View* view) : view_(view) {
-    view_->AddObserver(this);
-  }
-  ~BoundsChangeObserver() override { view_->RemoveObserver(this); }
-
-  Changes GetAndClearChanges() {
-    Changes changes;
-    changes.swap(changes_);
-    return changes;
-  }
-
- private:
-  // Overridden from ViewObserver:
-  void OnViewBoundsChanging(View* view,
-                            const mojo::Rect& old_bounds,
-                            const mojo::Rect& new_bounds) override {
-    changes_.push_back(base::StringPrintf(
-        "view=%s old_bounds=%s new_bounds=%s phase=changing",
-        ViewIdToString(view->id()).c_str(), RectToString(old_bounds).c_str(),
-        RectToString(new_bounds).c_str()));
-  }
-  void OnViewBoundsChanged(View* view,
-                           const mojo::Rect& old_bounds,
-                           const mojo::Rect& new_bounds) override {
-    changes_.push_back(base::StringPrintf(
-        "view=%s old_bounds=%s new_bounds=%s phase=changed",
-        ViewIdToString(view->id()).c_str(), RectToString(old_bounds).c_str(),
-        RectToString(new_bounds).c_str()));
-  }
-
-  View* view_;
-  Changes changes_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver);
-};
-
-}  // namespace
-
-TEST_F(ViewObserverTest, SetBounds) {
-  TestView v1;
-  {
-    BoundsChangeObserver observer(&v1);
-    mojo::Rect rect;
-    rect.width = rect.height = 100;
-    v1.SetBounds(rect);
-
-    Changes changes = observer.GetAndClearChanges();
-    ASSERT_EQ(2U, changes.size());
-    EXPECT_EQ(
-        "view=0,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100 phase=changing",
-        changes[0]);
-    EXPECT_EQ(
-        "view=0,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100 phase=changed",
-        changes[1]);
-  }
-}
-
-namespace {
-
-class VisibilityChangeObserver : public ViewObserver {
- public:
-  explicit VisibilityChangeObserver(View* view) : view_(view) {
-    view_->AddObserver(this);
-  }
-  ~VisibilityChangeObserver() override { view_->RemoveObserver(this); }
-
-  Changes GetAndClearChanges() {
-    Changes changes;
-    changes.swap(changes_);
-    return changes;
-  }
-
- private:
-  // Overridden from ViewObserver:
-  void OnViewVisibilityChanging(View* view) override {
-    changes_.push_back(
-        base::StringPrintf("view=%s phase=changing visibility=%s",
-                           ViewIdToString(view->id()).c_str(),
-                           view->visible() ? "true" : "false"));
-  }
-  void OnViewVisibilityChanged(View* view) override {
-    changes_.push_back(base::StringPrintf("view=%s phase=changed visibility=%s",
-                                          ViewIdToString(view->id()).c_str(),
-                                          view->visible() ? "true" : "false"));
-  }
-
-  View* view_;
-  Changes changes_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver);
-};
-
-}  // namespace
-
-TEST_F(ViewObserverTest, SetVisible) {
-  TestView v1;
-  EXPECT_TRUE(v1.visible());
-  {
-    // Change visibility from true to false and make sure we get notifications.
-    VisibilityChangeObserver observer(&v1);
-    v1.SetVisible(false);
-
-    Changes changes = observer.GetAndClearChanges();
-    ASSERT_EQ(2U, changes.size());
-    EXPECT_EQ("view=0,1 phase=changing visibility=true", changes[0]);
-    EXPECT_EQ("view=0,1 phase=changed visibility=false", changes[1]);
-  }
-  {
-    // Set visible to existing value and verify no notifications.
-    VisibilityChangeObserver observer(&v1);
-    v1.SetVisible(false);
-    EXPECT_TRUE(observer.GetAndClearChanges().empty());
-  }
-}
-
-TEST_F(ViewObserverTest, SetVisibleParent) {
-  TestView parent;
-  ViewPrivate(&parent).set_id(1);
-  TestView child;
-  ViewPrivate(&child).set_id(2);
-  parent.AddChild(&child);
-  EXPECT_TRUE(parent.visible());
-  EXPECT_TRUE(child.visible());
-  {
-    // Change visibility from true to false and make sure we get notifications
-    // on the parent.
-    VisibilityChangeObserver observer(&parent);
-    child.SetVisible(false);
-
-    Changes changes = observer.GetAndClearChanges();
-    ASSERT_EQ(1U, changes.size());
-    EXPECT_EQ("view=0,2 phase=changed visibility=false", changes[0]);
-  }
-}
-
-TEST_F(ViewObserverTest, SetVisibleChild) {
-  TestView parent;
-  ViewPrivate(&parent).set_id(1);
-  TestView child;
-  ViewPrivate(&child).set_id(2);
-  parent.AddChild(&child);
-  EXPECT_TRUE(parent.visible());
-  EXPECT_TRUE(child.visible());
-  {
-    // Change visibility from true to false and make sure we get notifications
-    // on the child.
-    VisibilityChangeObserver observer(&child);
-    parent.SetVisible(false);
-
-    Changes changes = observer.GetAndClearChanges();
-    ASSERT_EQ(1U, changes.size());
-    EXPECT_EQ("view=0,1 phase=changed visibility=false", changes[0]);
-  }
-}
-
-namespace {
-
-class SharedPropertyChangeObserver : public ViewObserver {
- public:
-  explicit SharedPropertyChangeObserver(View* view) : view_(view) {
-    view_->AddObserver(this);
-  }
-  ~SharedPropertyChangeObserver() override { view_->RemoveObserver(this); }
-
-  Changes GetAndClearChanges() {
-    Changes changes;
-    changes.swap(changes_);
-    return changes;
-  }
-
- private:
-  // Overridden from ViewObserver:
-  void OnViewSharedPropertyChanged(
-      View* view,
-      const std::string& name,
-      const std::vector<uint8_t>* old_data,
-      const std::vector<uint8_t>* new_data) override {
-    changes_.push_back(base::StringPrintf(
-        "view=%s shared property changed key=%s old_value=%s new_value=%s",
-        ViewIdToString(view->id()).c_str(), name.c_str(),
-        VectorToString(old_data).c_str(), VectorToString(new_data).c_str()));
-  }
-
-  std::string VectorToString(const std::vector<uint8_t>* data) {
-    if (!data)
-      return "NULL";
-    std::string s;
-    for (char c : *data)
-      s += c;
-    return s;
-  }
-
-  View* view_;
-  Changes changes_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(SharedPropertyChangeObserver);
-};
-
-}  // namespace
-
-TEST_F(ViewObserverTest, SetLocalProperty) {
-  TestView v1;
-  std::vector<uint8_t> one(1, '1');
-
-  {
-    // Change visibility from true to false and make sure we get notifications.
-    SharedPropertyChangeObserver observer(&v1);
-    v1.SetSharedProperty("one", &one);
-    Changes changes = observer.GetAndClearChanges();
-    ASSERT_EQ(1U, changes.size());
-    EXPECT_EQ(
-        "view=0,1 shared property changed key=one old_value=NULL new_value=1",
-        changes[0]);
-    EXPECT_EQ(1U, v1.shared_properties().size());
-  }
-  {
-    // Set visible to existing value and verify no notifications.
-    SharedPropertyChangeObserver observer(&v1);
-    v1.SetSharedProperty("one", &one);
-    EXPECT_TRUE(observer.GetAndClearChanges().empty());
-    EXPECT_EQ(1U, v1.shared_properties().size());
-  }
-  {
-    // Set the value to NULL to delete it.
-    // Change visibility from true to false and make sure we get notifications.
-    SharedPropertyChangeObserver observer(&v1);
-    v1.SetSharedProperty("one", NULL);
-    Changes changes = observer.GetAndClearChanges();
-    ASSERT_EQ(1U, changes.size());
-    EXPECT_EQ(
-        "view=0,1 shared property changed key=one old_value=1 new_value=NULL",
-        changes[0]);
-    EXPECT_EQ(0U, v1.shared_properties().size());
-  }
-  {
-    // Setting a null property to null shouldn't update us.
-    SharedPropertyChangeObserver observer(&v1);
-    v1.SetSharedProperty("one", NULL);
-    EXPECT_TRUE(observer.GetAndClearChanges().empty());
-    EXPECT_EQ(0U, v1.shared_properties().size());
-  }
-}
-
-namespace {
-
-typedef std::pair<const void*, intptr_t> PropertyChangeInfo;
-
-class LocalPropertyChangeObserver : public ViewObserver {
- public:
-  explicit LocalPropertyChangeObserver(View* view)
-      : view_(view), property_key_(nullptr), old_property_value_(-1) {
-    view_->AddObserver(this);
-  }
-  ~LocalPropertyChangeObserver() override { view_->RemoveObserver(this); }
-
-  PropertyChangeInfo PropertyChangeInfoAndClear() {
-    PropertyChangeInfo result(property_key_, old_property_value_);
-    property_key_ = NULL;
-    old_property_value_ = -3;
-    return result;
-  }
-
- private:
-  void OnViewLocalPropertyChanged(View* window,
-                                  const void* key,
-                                  intptr_t old) override {
-    property_key_ = key;
-    old_property_value_ = old;
-  }
-
-  View* view_;
-  const void* property_key_;
-  intptr_t old_property_value_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(LocalPropertyChangeObserver);
-};
-
-}  // namespace
-
-TEST_F(ViewObserverTest, LocalPropertyChanged) {
-  TestView v1;
-  LocalPropertyChangeObserver o(&v1);
-
-  static const ViewProperty<int> prop = {-2};
-
-  v1.SetLocalProperty(&prop, 1);
-  EXPECT_EQ(PropertyChangeInfo(&prop, -2), o.PropertyChangeInfoAndClear());
-  v1.SetLocalProperty(&prop, -2);
-  EXPECT_EQ(PropertyChangeInfo(&prop, 1), o.PropertyChangeInfoAndClear());
-  v1.SetLocalProperty(&prop, 3);
-  EXPECT_EQ(PropertyChangeInfo(&prop, -2), o.PropertyChangeInfoAndClear());
-  v1.ClearLocalProperty(&prop);
-  EXPECT_EQ(PropertyChangeInfo(&prop, 3), o.PropertyChangeInfoAndClear());
-
-  // Sanity check to see if |PropertyChangeInfoAndClear| really clears.
-  EXPECT_EQ(PropertyChangeInfo(reinterpret_cast<const void*>(NULL), -3),
-            o.PropertyChangeInfoAndClear());
-}
-
-}  // namespace mus
diff --git a/components/mus/public/cpp/tests/view_manager_test_base.cc b/components/mus/public/cpp/tests/window_server_test_base.cc
similarity index 62%
rename from components/mus/public/cpp/tests/view_manager_test_base.cc
rename to components/mus/public/cpp/tests/window_server_test_base.cc
index e4bf2ba..649fc24 100644
--- a/components/mus/public/cpp/tests/view_manager_test_base.cc
+++ b/components/mus/public/cpp/tests/window_server_test_base.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/mus/public/cpp/tests/view_manager_test_base.h"
+#include "components/mus/public/cpp/tests/window_server_test_base.h"
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/test_timeouts.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
-#include "components/mus/public/cpp/view_tree_host_factory.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_host_factory.h"
 #include "mojo/application/public/cpp/application_impl.h"
 
 namespace mus {
@@ -26,15 +26,15 @@
 
 }  // namespace
 
-ViewManagerTestBase::ViewManagerTestBase()
+WindowServerTestBase::WindowServerTestBase()
     : most_recent_connection_(nullptr),
       window_manager_(nullptr),
-      view_tree_connection_destroyed_(false) {}
+      window_tree_connection_destroyed_(false) {}
 
-ViewManagerTestBase::~ViewManagerTestBase() {}
+WindowServerTestBase::~WindowServerTestBase() {}
 
 // static
-bool ViewManagerTestBase::DoRunLoopWithTimeout() {
+bool WindowServerTestBase::DoRunLoopWithTimeout() {
   if (current_run_loop != nullptr)
     return false;
 
@@ -51,7 +51,7 @@
 }
 
 // static
-bool ViewManagerTestBase::QuitRunLoop() {
+bool WindowServerTestBase::QuitRunLoop() {
   if (!current_run_loop)
     return false;
 
@@ -60,44 +60,44 @@
   return true;
 }
 
-void ViewManagerTestBase::SetUp() {
+void WindowServerTestBase::SetUp() {
   ApplicationTestBase::SetUp();
 
-  CreateSingleViewTreeHost(application_impl(), this, &host_);
+  CreateSingleWindowTreeHost(application_impl(), this, &host_);
 
   ASSERT_TRUE(DoRunLoopWithTimeout());  // RunLoop should be quit by OnEmbed().
   std::swap(window_manager_, most_recent_connection_);
 }
 
-void ViewManagerTestBase::TearDown() {
+void WindowServerTestBase::TearDown() {
   ApplicationTestBase::TearDown();
 }
 
-mojo::ApplicationDelegate* ViewManagerTestBase::GetApplicationDelegate() {
+mojo::ApplicationDelegate* WindowServerTestBase::GetApplicationDelegate() {
   return this;
 }
 
-bool ViewManagerTestBase::ConfigureIncomingConnection(
+bool WindowServerTestBase::ConfigureIncomingConnection(
     mojo::ApplicationConnection* connection) {
   connection->AddService<mojo::ViewTreeClient>(this);
   return true;
 }
 
-void ViewManagerTestBase::OnEmbed(View* root) {
+void WindowServerTestBase::OnEmbed(Window* root) {
   most_recent_connection_ = root->connection();
   EXPECT_TRUE(QuitRunLoop());
 }
 
-void ViewManagerTestBase::OnConnectionLost(ViewTreeConnection* connection) {
-  view_tree_connection_destroyed_ = true;
+void WindowServerTestBase::OnConnectionLost(WindowTreeConnection* connection) {
+  window_tree_connection_destroyed_ = true;
 }
 
-void ViewManagerTestBase::Create(
+void WindowServerTestBase::Create(
     mojo::ApplicationConnection* connection,
     mojo::InterfaceRequest<mojo::ViewTreeClient> request) {
-  ViewTreeConnection::Create(
+  WindowTreeConnection::Create(
       this, request.Pass(),
-      ViewTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
+      WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
 }
 
 }  // namespace mus
diff --git a/components/mus/public/cpp/tests/view_manager_test_base.h b/components/mus/public/cpp/tests/window_server_test_base.h
similarity index 63%
rename from components/mus/public/cpp/tests/view_manager_test_base.h
rename to components/mus/public/cpp/tests/window_server_test_base.h
index a1529f3..b46c871 100644
--- a/components/mus/public/cpp/tests/view_manager_test_base.h
+++ b/components/mus/public/cpp/tests/window_server_test_base.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_MUS_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_BASE_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_BASE_H_
+#ifndef COMPONENTS_MUS_PUBLIC_CPP_TESTS_WINDOW_SERVER_TEST_BASE_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_TESTS_WINDOW_SERVER_TEST_BASE_H_
 
 #include "base/memory/scoped_ptr.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
 #include "components/mus/public/interfaces/view_tree.mojom.h"
 #include "components/mus/public/interfaces/view_tree_host.mojom.h"
 #include "mojo/application/public/cpp/application_delegate.h"
@@ -15,22 +15,22 @@
 
 namespace mus {
 
-// ViewManagerTestBase is a base class for use with app tests that use
-// ViewManager. SetUp() connects to the ViewManager and blocks until OnEmbed()
-// has been invoked. window_manager() can be used to access the ViewManager
+// WindowServerTestBase is a base class for use with app tests that use
+// WindowServer. SetUp() connects to the WindowServer and blocks until OnEmbed()
+// has been invoked. window_manager() can be used to access the WindowServer
 // established as part of SetUp().
-class ViewManagerTestBase
+class WindowServerTestBase
     : public mojo::test::ApplicationTestBase,
       public mojo::ApplicationDelegate,
-      public ViewTreeDelegate,
+      public WindowTreeDelegate,
       public mojo::InterfaceFactory<mojo::ViewTreeClient> {
  public:
-  ViewManagerTestBase();
-  ~ViewManagerTestBase() override;
+  WindowServerTestBase();
+  ~WindowServerTestBase() override;
 
-  // True if ViewTreeDelegate::OnConnectionLost() was called.
-  bool view_tree_connection_destroyed() const {
-    return view_tree_connection_destroyed_;
+  // True if WindowTreeDelegate::OnConnectionLost() was called.
+  bool window_tree_connection_destroyed() const {
+    return window_tree_connection_destroyed_;
   }
 
   // Runs the MessageLoop until QuitRunLoop() is called, or a timeout occurs.
@@ -42,10 +42,10 @@
   // success, false if a RunLoop isn't running.
   static bool QuitRunLoop() WARN_UNUSED_RESULT;
 
-  ViewTreeConnection* window_manager() { return window_manager_; }
+  WindowTreeConnection* window_manager() { return window_manager_; }
 
  protected:
-  ViewTreeConnection* most_recent_connection() {
+  WindowTreeConnection* most_recent_connection() {
     return most_recent_connection_;
   }
 
@@ -60,9 +60,9 @@
   bool ConfigureIncomingConnection(
       mojo::ApplicationConnection* connection) override;
 
-  // ViewTreeDelegate:
-  void OnEmbed(View* root) override;
-  void OnConnectionLost(ViewTreeConnection* connection) override;
+  // WindowTreeDelegate:
+  void OnEmbed(Window* root) override;
+  void OnConnectionLost(WindowTreeConnection* connection) override;
 
   // InterfaceFactory<ViewTreeClient>:
   void Create(mojo::ApplicationConnection* connection,
@@ -70,20 +70,20 @@
 
   // Used to receive the most recent view tree connection loaded by an embed
   // action.
-  ViewTreeConnection* most_recent_connection_;
+  WindowTreeConnection* most_recent_connection_;
 
  private:
   mojo::ViewTreeHostPtr host_;
 
   // The View Manager connection held by the window manager (app running at the
   // root view).
-  ViewTreeConnection* window_manager_;
+  WindowTreeConnection* window_manager_;
 
-  bool view_tree_connection_destroyed_;
+  bool window_tree_connection_destroyed_;
 
-  MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerTestBase);
+  MOJO_DISALLOW_COPY_AND_ASSIGN(WindowServerTestBase);
 };
 
 }  // namespace mus
 
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_TESTS_VIEW_MANAGER_TEST_BASE_H_
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_TESTS_WINDOW_SERVER_TEST_BASE_H_
diff --git a/components/mus/public/cpp/tests/view_manager_test_suite.cc b/components/mus/public/cpp/tests/window_server_test_suite.cc
similarity index 75%
rename from components/mus/public/cpp/tests/view_manager_test_suite.cc
rename to components/mus/public/cpp/tests/window_server_test_suite.cc
index a1e0c98d..ea1a04c0 100644
--- a/components/mus/public/cpp/tests/view_manager_test_suite.cc
+++ b/components/mus/public/cpp/tests/window_server_test_suite.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/mus/public/cpp/tests/view_manager_test_suite.h"
+#include "components/mus/public/cpp/tests/window_server_test_suite.h"
 
 #include "base/i18n/icu_util.h"
 
@@ -12,12 +12,12 @@
 
 namespace mus {
 
-ViewManagerTestSuite::ViewManagerTestSuite(int argc, char** argv)
+WindowServerTestSuite::WindowServerTestSuite(int argc, char** argv)
     : TestSuite(argc, argv) {}
 
-ViewManagerTestSuite::~ViewManagerTestSuite() {}
+WindowServerTestSuite::~WindowServerTestSuite() {}
 
-void ViewManagerTestSuite::Initialize() {
+void WindowServerTestSuite::Initialize() {
 #if defined(USE_X11)
   // Each test ends up creating a new thread for the native viewport service.
   // In other words we'll use X on different threads, so tell it that.
diff --git a/components/mus/public/cpp/tests/window_server_test_suite.h b/components/mus/public/cpp/tests/window_server_test_suite.h
new file mode 100644
index 0000000..cbc2eb77
--- /dev/null
+++ b/components/mus/public/cpp/tests/window_server_test_suite.h
@@ -0,0 +1,27 @@
+// 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 COMPONENTS_MUS_PUBLIC_CPP_TESTS_WINDOW_SERVER_TEST_SUITE_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_TESTS_WINDOW_SERVER_TEST_SUITE_H_
+
+#include "base/test/test_suite.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/macros.h"
+
+namespace mus {
+
+class WindowServerTestSuite : public base::TestSuite {
+ public:
+  WindowServerTestSuite(int argc, char** argv);
+  ~WindowServerTestSuite() override;
+
+ protected:
+  void Initialize() override;
+
+ private:
+  MOJO_DISALLOW_COPY_AND_ASSIGN(WindowServerTestSuite);
+};
+
+}  // namespace mus
+
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_TESTS_WINDOW_SERVER_TEST_SUITE_H_
diff --git a/components/mus/public/cpp/tests/window_unittest.cc b/components/mus/public/cpp/tests/window_unittest.cc
new file mode 100644
index 0000000..870a026
--- /dev/null
+++ b/components/mus/public/cpp/tests/window_unittest.cc
@@ -0,0 +1,875 @@
+// 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 "components/mus/public/cpp/window.h"
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "components/mus/public/cpp/lib/window_private.h"
+#include "components/mus/public/cpp/util.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_property.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mus {
+
+// Window ---------------------------------------------------------------------
+
+typedef testing::Test WindowTest;
+
+// Subclass with public ctor/dtor.
+class TestWindow : public Window {
+ public:
+  TestWindow() { WindowPrivate(this).set_id(1); }
+  ~TestWindow() {}
+
+ private:
+  MOJO_DISALLOW_COPY_AND_ASSIGN(TestWindow);
+};
+
+TEST_F(WindowTest, AddChild) {
+  TestWindow w1;
+  TestWindow w11;
+  w1.AddChild(&w11);
+  EXPECT_EQ(1U, w1.children().size());
+}
+
+TEST_F(WindowTest, RemoveChild) {
+  TestWindow w1;
+  TestWindow w11;
+  w1.AddChild(&w11);
+  EXPECT_EQ(1U, w1.children().size());
+  w1.RemoveChild(&w11);
+  EXPECT_EQ(0U, w1.children().size());
+}
+
+TEST_F(WindowTest, Reparent) {
+  TestWindow w1;
+  TestWindow w2;
+  TestWindow w11;
+  w1.AddChild(&w11);
+  EXPECT_EQ(1U, w1.children().size());
+  w2.AddChild(&w11);
+  EXPECT_EQ(1U, w2.children().size());
+  EXPECT_EQ(0U, w1.children().size());
+}
+
+TEST_F(WindowTest, Contains) {
+  TestWindow w1;
+
+  // Direct descendant.
+  TestWindow w11;
+  w1.AddChild(&w11);
+  EXPECT_TRUE(w1.Contains(&w11));
+
+  // Indirect descendant.
+  TestWindow w111;
+  w11.AddChild(&w111);
+  EXPECT_TRUE(w1.Contains(&w111));
+}
+
+TEST_F(WindowTest, GetChildById) {
+  TestWindow w1;
+  WindowPrivate(&w1).set_id(1);
+  TestWindow w11;
+  WindowPrivate(&w11).set_id(11);
+  w1.AddChild(&w11);
+  TestWindow w111;
+  WindowPrivate(&w111).set_id(111);
+  w11.AddChild(&w111);
+
+  // Find direct & indirect descendents.
+  EXPECT_EQ(&w11, w1.GetChildById(w11.id()));
+  EXPECT_EQ(&w111, w1.GetChildById(w111.id()));
+}
+
+TEST_F(WindowTest, DrawnAndVisible) {
+  TestWindow w1;
+  EXPECT_TRUE(w1.visible());
+  EXPECT_FALSE(w1.IsDrawn());
+
+  WindowPrivate(&w1).set_drawn(true);
+
+  TestWindow w11;
+  w1.AddChild(&w11);
+  EXPECT_TRUE(w11.visible());
+  EXPECT_TRUE(w11.IsDrawn());
+
+  w1.RemoveChild(&w11);
+  EXPECT_TRUE(w11.visible());
+  EXPECT_FALSE(w11.IsDrawn());
+}
+
+namespace {
+DEFINE_WINDOW_PROPERTY_KEY(int, kIntKey, -2);
+DEFINE_WINDOW_PROPERTY_KEY(const char*, kStringKey, "squeamish");
+}
+
+TEST_F(WindowTest, Property) {
+  TestWindow w;
+
+  // Non-existent properties should return the default walues.
+  EXPECT_EQ(-2, w.GetLocalProperty(kIntKey));
+  EXPECT_EQ(std::string("squeamish"), w.GetLocalProperty(kStringKey));
+
+  // A set property walue should be returned again (even if it's the default
+  // walue).
+  w.SetLocalProperty(kIntKey, INT_MAX);
+  EXPECT_EQ(INT_MAX, w.GetLocalProperty(kIntKey));
+  w.SetLocalProperty(kIntKey, -2);
+  EXPECT_EQ(-2, w.GetLocalProperty(kIntKey));
+  w.SetLocalProperty(kIntKey, INT_MIN);
+  EXPECT_EQ(INT_MIN, w.GetLocalProperty(kIntKey));
+
+  w.SetLocalProperty(kStringKey, static_cast<const char*>(NULL));
+  EXPECT_EQ(NULL, w.GetLocalProperty(kStringKey));
+  w.SetLocalProperty(kStringKey, "squeamish");
+  EXPECT_EQ(std::string("squeamish"), w.GetLocalProperty(kStringKey));
+  w.SetLocalProperty(kStringKey, "ossifrage");
+  EXPECT_EQ(std::string("ossifrage"), w.GetLocalProperty(kStringKey));
+
+  // ClearProperty should restore the default walue.
+  w.ClearLocalProperty(kIntKey);
+  EXPECT_EQ(-2, w.GetLocalProperty(kIntKey));
+  w.ClearLocalProperty(kStringKey);
+  EXPECT_EQ(std::string("squeamish"), w.GetLocalProperty(kStringKey));
+}
+
+namespace {
+
+class TestProperty {
+ public:
+  TestProperty() {}
+  virtual ~TestProperty() { last_deleted_ = this; }
+  static TestProperty* last_deleted() { return last_deleted_; }
+
+ private:
+  static TestProperty* last_deleted_;
+  MOJO_DISALLOW_COPY_AND_ASSIGN(TestProperty);
+};
+
+TestProperty* TestProperty::last_deleted_ = NULL;
+
+DEFINE_OWNED_WINDOW_PROPERTY_KEY(TestProperty, kOwnedKey, NULL);
+
+}  // namespace
+
+TEST_F(WindowTest, OwnedProperty) {
+  TestProperty* p3 = NULL;
+  {
+    TestWindow w;
+    EXPECT_EQ(NULL, w.GetLocalProperty(kOwnedKey));
+    TestProperty* p1 = new TestProperty();
+    w.SetLocalProperty(kOwnedKey, p1);
+    EXPECT_EQ(p1, w.GetLocalProperty(kOwnedKey));
+    EXPECT_EQ(NULL, TestProperty::last_deleted());
+
+    TestProperty* p2 = new TestProperty();
+    w.SetLocalProperty(kOwnedKey, p2);
+    EXPECT_EQ(p2, w.GetLocalProperty(kOwnedKey));
+    EXPECT_EQ(p1, TestProperty::last_deleted());
+
+    w.ClearLocalProperty(kOwnedKey);
+    EXPECT_EQ(NULL, w.GetLocalProperty(kOwnedKey));
+    EXPECT_EQ(p2, TestProperty::last_deleted());
+
+    p3 = new TestProperty();
+    w.SetLocalProperty(kOwnedKey, p3);
+    EXPECT_EQ(p3, w.GetLocalProperty(kOwnedKey));
+    EXPECT_EQ(p2, TestProperty::last_deleted());
+  }
+
+  EXPECT_EQ(p3, TestProperty::last_deleted());
+}
+
+// WindowObserver --------------------------------------------------------
+
+typedef testing::Test WindowObserverTest;
+
+bool TreeChangeParamsMatch(const WindowObserver::TreeChangeParams& lhs,
+                           const WindowObserver::TreeChangeParams& rhs) {
+  return lhs.target == rhs.target && lhs.old_parent == rhs.old_parent &&
+         lhs.new_parent == rhs.new_parent && lhs.receiver == rhs.receiver;
+}
+
+class TreeChangeObserver : public WindowObserver {
+ public:
+  explicit TreeChangeObserver(Window* observee) : observee_(observee) {
+    observee_->AddObserver(this);
+  }
+  ~TreeChangeObserver() override { observee_->RemoveObserver(this); }
+
+  void Reset() { received_params_.clear(); }
+
+  const std::vector<TreeChangeParams>& received_params() {
+    return received_params_;
+  }
+
+ private:
+  // Overridden from WindowObserver:
+  void OnTreeChanging(const TreeChangeParams& params) override {
+    received_params_.push_back(params);
+  }
+  void OnTreeChanged(const TreeChangeParams& params) override {
+    received_params_.push_back(params);
+  }
+
+  Window* observee_;
+  std::vector<TreeChangeParams> received_params_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(TreeChangeObserver);
+};
+
+// Adds/Removes w11 to w1.
+TEST_F(WindowObserverTest, TreeChange_SimpleAddRemove) {
+  TestWindow w1;
+  TreeChangeObserver o1(&w1);
+  EXPECT_TRUE(o1.received_params().empty());
+
+  TestWindow w11;
+  TreeChangeObserver o11(&w11);
+  EXPECT_TRUE(o11.received_params().empty());
+
+  // Add.
+
+  w1.AddChild(&w11);
+
+  EXPECT_EQ(2U, o1.received_params().size());
+  WindowObserver::TreeChangeParams p1;
+  p1.target = &w11;
+  p1.receiver = &w1;
+  p1.old_parent = NULL;
+  p1.new_parent = &w1;
+  EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back()));
+
+  EXPECT_EQ(2U, o11.received_params().size());
+  WindowObserver::TreeChangeParams p11 = p1;
+  p11.receiver = &w11;
+  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front()));
+  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back()));
+
+  o1.Reset();
+  o11.Reset();
+  EXPECT_TRUE(o1.received_params().empty());
+  EXPECT_TRUE(o11.received_params().empty());
+
+  // Remove.
+
+  w1.RemoveChild(&w11);
+
+  EXPECT_EQ(2U, o1.received_params().size());
+  p1.target = &w11;
+  p1.receiver = &w1;
+  p1.old_parent = &w1;
+  p1.new_parent = NULL;
+  EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front()));
+
+  EXPECT_EQ(2U, o11.received_params().size());
+  p11 = p1;
+  p11.receiver = &w11;
+  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front()));
+  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back()));
+}
+
+// Creates these two trees:
+// w1
+//  +- w11
+// w111
+//  +- w1111
+//  +- w1112
+// Then adds/removes w111 from w11.
+TEST_F(WindowObserverTest, TreeChange_NestedAddRemove) {
+  TestWindow w1, w11, w111, w1111, w1112;
+
+  // Root tree.
+  w1.AddChild(&w11);
+
+  // Tree to be attached.
+  w111.AddChild(&w1111);
+  w111.AddChild(&w1112);
+
+  TreeChangeObserver o1(&w1), o11(&w11), o111(&w111), o1111(&w1111),
+      o1112(&w1112);
+  WindowObserver::TreeChangeParams p1, p11, p111, p1111, p1112;
+
+  // Add.
+
+  w11.AddChild(&w111);
+
+  EXPECT_EQ(2U, o1.received_params().size());
+  p1.target = &w111;
+  p1.receiver = &w1;
+  p1.old_parent = NULL;
+  p1.new_parent = &w11;
+  EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back()));
+
+  EXPECT_EQ(2U, o11.received_params().size());
+  p11 = p1;
+  p11.receiver = &w11;
+  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back()));
+
+  EXPECT_EQ(2U, o111.received_params().size());
+  p111 = p11;
+  p111.receiver = &w111;
+  EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front()));
+  EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back()));
+
+  EXPECT_EQ(2U, o1111.received_params().size());
+  p1111 = p111;
+  p1111.receiver = &w1111;
+  EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().front()));
+  EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().back()));
+
+  EXPECT_EQ(2U, o1112.received_params().size());
+  p1112 = p111;
+  p1112.receiver = &w1112;
+  EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().front()));
+  EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().back()));
+
+  // Remove.
+  o1.Reset();
+  o11.Reset();
+  o111.Reset();
+  o1111.Reset();
+  o1112.Reset();
+  EXPECT_TRUE(o1.received_params().empty());
+  EXPECT_TRUE(o11.received_params().empty());
+  EXPECT_TRUE(o111.received_params().empty());
+  EXPECT_TRUE(o1111.received_params().empty());
+  EXPECT_TRUE(o1112.received_params().empty());
+
+  w11.RemoveChild(&w111);
+
+  EXPECT_EQ(2U, o1.received_params().size());
+  p1.target = &w111;
+  p1.receiver = &w1;
+  p1.old_parent = &w11;
+  p1.new_parent = NULL;
+  EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front()));
+
+  EXPECT_EQ(2U, o11.received_params().size());
+  p11 = p1;
+  p11.receiver = &w11;
+  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front()));
+
+  EXPECT_EQ(2U, o111.received_params().size());
+  p111 = p11;
+  p111.receiver = &w111;
+  EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front()));
+  EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back()));
+
+  EXPECT_EQ(2U, o1111.received_params().size());
+  p1111 = p111;
+  p1111.receiver = &w1111;
+  EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().front()));
+  EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().back()));
+
+  EXPECT_EQ(2U, o1112.received_params().size());
+  p1112 = p111;
+  p1112.receiver = &w1112;
+  EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().front()));
+  EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().back()));
+}
+
+TEST_F(WindowObserverTest, TreeChange_Reparent) {
+  TestWindow w1, w11, w12, w111;
+  w1.AddChild(&w11);
+  w1.AddChild(&w12);
+  w11.AddChild(&w111);
+
+  TreeChangeObserver o1(&w1), o11(&w11), o12(&w12), o111(&w111);
+
+  // Reparent.
+  w12.AddChild(&w111);
+
+  // w1 (root) should see both changing and changed notifications.
+  EXPECT_EQ(4U, o1.received_params().size());
+  WindowObserver::TreeChangeParams p1;
+  p1.target = &w111;
+  p1.receiver = &w1;
+  p1.old_parent = &w11;
+  p1.new_parent = &w12;
+  EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front()));
+  EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back()));
+
+  // w11 should see changing notifications.
+  EXPECT_EQ(2U, o11.received_params().size());
+  WindowObserver::TreeChangeParams p11;
+  p11 = p1;
+  p11.receiver = &w11;
+  EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front()));
+
+  // w12 should see changed notifications.
+  EXPECT_EQ(2U, o12.received_params().size());
+  WindowObserver::TreeChangeParams p12;
+  p12 = p1;
+  p12.receiver = &w12;
+  EXPECT_TRUE(TreeChangeParamsMatch(p12, o12.received_params().back()));
+
+  // w111 should see both changing and changed notifications.
+  EXPECT_EQ(2U, o111.received_params().size());
+  WindowObserver::TreeChangeParams p111;
+  p111 = p1;
+  p111.receiver = &w111;
+  EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front()));
+  EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back()));
+}
+
+namespace {
+
+class OrderChangeObserver : public WindowObserver {
+ public:
+  struct Change {
+    Window* window;
+    Window* relative_window;
+    mojo::OrderDirection direction;
+  };
+  typedef std::vector<Change> Changes;
+
+  explicit OrderChangeObserver(Window* observee) : observee_(observee) {
+    observee_->AddObserver(this);
+  }
+  ~OrderChangeObserver() override { observee_->RemoveObserver(this); }
+
+  Changes GetAndClearChanges() {
+    Changes changes;
+    changes_.swap(changes);
+    return changes;
+  }
+
+ private:
+  // Overridden from WindowObserver:
+  void OnWindowReordering(Window* window,
+                          Window* relative_window,
+                          mojo::OrderDirection direction) override {
+    OnWindowReordered(window, relative_window, direction);
+  }
+
+  void OnWindowReordered(Window* window,
+                         Window* relative_window,
+                         mojo::OrderDirection direction) override {
+    Change change;
+    change.window = window;
+    change.relative_window = relative_window;
+    change.direction = direction;
+    changes_.push_back(change);
+  }
+
+  Window* observee_;
+  Changes changes_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver);
+};
+
+}  // namespace
+
+TEST_F(WindowObserverTest, Order) {
+  TestWindow w1, w11, w12, w13;
+  w1.AddChild(&w11);
+  w1.AddChild(&w12);
+  w1.AddChild(&w13);
+
+  // Order: w11, w12, w13
+  EXPECT_EQ(3U, w1.children().size());
+  EXPECT_EQ(&w11, w1.children().front());
+  EXPECT_EQ(&w13, w1.children().back());
+
+  {
+    OrderChangeObserver observer(&w11);
+
+    // Move w11 to front.
+    // Resulting order: w12, w13, w11
+    w11.MoveToFront();
+    EXPECT_EQ(&w12, w1.children().front());
+    EXPECT_EQ(&w11, w1.children().back());
+
+    OrderChangeObserver::Changes changes = observer.GetAndClearChanges();
+    ASSERT_EQ(2U, changes.size());
+    EXPECT_EQ(&w11, changes[0].window);
+    EXPECT_EQ(&w13, changes[0].relative_window);
+    EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[0].direction);
+
+    EXPECT_EQ(&w11, changes[1].window);
+    EXPECT_EQ(&w13, changes[1].relative_window);
+    EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[1].direction);
+  }
+
+  {
+    OrderChangeObserver observer(&w11);
+
+    // Move w11 to back.
+    // Resulting order: w11, w12, w13
+    w11.MoveToBack();
+    EXPECT_EQ(&w11, w1.children().front());
+    EXPECT_EQ(&w13, w1.children().back());
+
+    OrderChangeObserver::Changes changes = observer.GetAndClearChanges();
+    ASSERT_EQ(2U, changes.size());
+    EXPECT_EQ(&w11, changes[0].window);
+    EXPECT_EQ(&w12, changes[0].relative_window);
+    EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[0].direction);
+
+    EXPECT_EQ(&w11, changes[1].window);
+    EXPECT_EQ(&w12, changes[1].relative_window);
+    EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[1].direction);
+  }
+
+  {
+    OrderChangeObserver observer(&w11);
+
+    // Move w11 above w12.
+    // Resulting order: w12. w11, w13
+    w11.Reorder(&w12, mojo::ORDER_DIRECTION_ABOVE);
+    EXPECT_EQ(&w12, w1.children().front());
+    EXPECT_EQ(&w13, w1.children().back());
+
+    OrderChangeObserver::Changes changes = observer.GetAndClearChanges();
+    ASSERT_EQ(2U, changes.size());
+    EXPECT_EQ(&w11, changes[0].window);
+    EXPECT_EQ(&w12, changes[0].relative_window);
+    EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[0].direction);
+
+    EXPECT_EQ(&w11, changes[1].window);
+    EXPECT_EQ(&w12, changes[1].relative_window);
+    EXPECT_EQ(mojo::ORDER_DIRECTION_ABOVE, changes[1].direction);
+  }
+
+  {
+    OrderChangeObserver observer(&w11);
+
+    // Move w11 below w12.
+    // Resulting order: w11, w12, w13
+    w11.Reorder(&w12, mojo::ORDER_DIRECTION_BELOW);
+    EXPECT_EQ(&w11, w1.children().front());
+    EXPECT_EQ(&w13, w1.children().back());
+
+    OrderChangeObserver::Changes changes = observer.GetAndClearChanges();
+    ASSERT_EQ(2U, changes.size());
+    EXPECT_EQ(&w11, changes[0].window);
+    EXPECT_EQ(&w12, changes[0].relative_window);
+    EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[0].direction);
+
+    EXPECT_EQ(&w11, changes[1].window);
+    EXPECT_EQ(&w12, changes[1].relative_window);
+    EXPECT_EQ(mojo::ORDER_DIRECTION_BELOW, changes[1].direction);
+  }
+}
+
+namespace {
+
+typedef std::vector<std::string> Changes;
+
+std::string WindowIdToString(Id id) {
+  return (id == 0) ? "null"
+                   : base::StringPrintf("%d,%d", HiWord(id), LoWord(id));
+}
+
+std::string RectToString(const mojo::Rect& rect) {
+  return base::StringPrintf("%d,%d %dx%d", rect.x, rect.y, rect.width,
+                            rect.height);
+}
+
+class BoundsChangeObserver : public WindowObserver {
+ public:
+  explicit BoundsChangeObserver(Window* window) : window_(window) {
+    window_->AddObserver(this);
+  }
+  ~BoundsChangeObserver() override { window_->RemoveObserver(this); }
+
+  Changes GetAndClearChanges() {
+    Changes changes;
+    changes.swap(changes_);
+    return changes;
+  }
+
+ private:
+  // Overridden from WindowObserver:
+  void OnWindowBoundsChanging(Window* window,
+                              const mojo::Rect& old_bounds,
+                              const mojo::Rect& new_bounds) override {
+    changes_.push_back(base::StringPrintf(
+        "window=%s old_bounds=%s new_bounds=%s phase=changing",
+        WindowIdToString(window->id()).c_str(),
+        RectToString(old_bounds).c_str(), RectToString(new_bounds).c_str()));
+  }
+  void OnWindowBoundsChanged(Window* window,
+                             const mojo::Rect& old_bounds,
+                             const mojo::Rect& new_bounds) override {
+    changes_.push_back(base::StringPrintf(
+        "window=%s old_bounds=%s new_bounds=%s phase=changed",
+        WindowIdToString(window->id()).c_str(),
+        RectToString(old_bounds).c_str(), RectToString(new_bounds).c_str()));
+  }
+
+  Window* window_;
+  Changes changes_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver);
+};
+
+}  // namespace
+
+TEST_F(WindowObserverTest, SetBounds) {
+  TestWindow w1;
+  {
+    BoundsChangeObserver observer(&w1);
+    mojo::Rect rect;
+    rect.width = rect.height = 100;
+    w1.SetBounds(rect);
+
+    Changes changes = observer.GetAndClearChanges();
+    ASSERT_EQ(2U, changes.size());
+    EXPECT_EQ(
+        "window=0,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100 phase=changing",
+        changes[0]);
+    EXPECT_EQ(
+        "window=0,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100 phase=changed",
+        changes[1]);
+  }
+}
+
+namespace {
+
+class VisibilityChangeObserver : public WindowObserver {
+ public:
+  explicit VisibilityChangeObserver(Window* window) : window_(window) {
+    window_->AddObserver(this);
+  }
+  ~VisibilityChangeObserver() override { window_->RemoveObserver(this); }
+
+  Changes GetAndClearChanges() {
+    Changes changes;
+    changes.swap(changes_);
+    return changes;
+  }
+
+ private:
+  // Overridden from WindowObserver:
+  void OnWindowVisibilityChanging(Window* window) override {
+    changes_.push_back(
+        base::StringPrintf("window=%s phase=changing wisibility=%s",
+                           WindowIdToString(window->id()).c_str(),
+                           window->visible() ? "true" : "false"));
+  }
+  void OnWindowVisibilityChanged(Window* window) override {
+    changes_.push_back(
+        base::StringPrintf("window=%s phase=changed wisibility=%s",
+                           WindowIdToString(window->id()).c_str(),
+                           window->visible() ? "true" : "false"));
+  }
+
+  Window* window_;
+  Changes changes_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver);
+};
+
+}  // namespace
+
+TEST_F(WindowObserverTest, SetVisible) {
+  TestWindow w1;
+  EXPECT_TRUE(w1.visible());
+  {
+    // Change wisibility from true to false and make sure we get notifications.
+    VisibilityChangeObserver observer(&w1);
+    w1.SetVisible(false);
+
+    Changes changes = observer.GetAndClearChanges();
+    ASSERT_EQ(2U, changes.size());
+    EXPECT_EQ("window=0,1 phase=changing wisibility=true", changes[0]);
+    EXPECT_EQ("window=0,1 phase=changed wisibility=false", changes[1]);
+  }
+  {
+    // Set visible to existing walue and werify no notifications.
+    VisibilityChangeObserver observer(&w1);
+    w1.SetVisible(false);
+    EXPECT_TRUE(observer.GetAndClearChanges().empty());
+  }
+}
+
+TEST_F(WindowObserverTest, SetVisibleParent) {
+  TestWindow parent;
+  WindowPrivate(&parent).set_id(1);
+  TestWindow child;
+  WindowPrivate(&child).set_id(2);
+  parent.AddChild(&child);
+  EXPECT_TRUE(parent.visible());
+  EXPECT_TRUE(child.visible());
+  {
+    // Change wisibility from true to false and make sure we get notifications
+    // on the parent.
+    VisibilityChangeObserver observer(&parent);
+    child.SetVisible(false);
+
+    Changes changes = observer.GetAndClearChanges();
+    ASSERT_EQ(1U, changes.size());
+    EXPECT_EQ("window=0,2 phase=changed wisibility=false", changes[0]);
+  }
+}
+
+TEST_F(WindowObserverTest, SetVisibleChild) {
+  TestWindow parent;
+  WindowPrivate(&parent).set_id(1);
+  TestWindow child;
+  WindowPrivate(&child).set_id(2);
+  parent.AddChild(&child);
+  EXPECT_TRUE(parent.visible());
+  EXPECT_TRUE(child.visible());
+  {
+    // Change wisibility from true to false and make sure we get notifications
+    // on the child.
+    VisibilityChangeObserver observer(&child);
+    parent.SetVisible(false);
+
+    Changes changes = observer.GetAndClearChanges();
+    ASSERT_EQ(1U, changes.size());
+    EXPECT_EQ("window=0,1 phase=changed wisibility=false", changes[0]);
+  }
+}
+
+namespace {
+
+class SharedPropertyChangeObserver : public WindowObserver {
+ public:
+  explicit SharedPropertyChangeObserver(Window* window) : window_(window) {
+    window_->AddObserver(this);
+  }
+  ~SharedPropertyChangeObserver() override { window_->RemoveObserver(this); }
+
+  Changes GetAndClearChanges() {
+    Changes changes;
+    changes.swap(changes_);
+    return changes;
+  }
+
+ private:
+  // Overridden from WindowObserver:
+  void OnWindowSharedPropertyChanged(
+      Window* window,
+      const std::string& name,
+      const std::vector<uint8_t>* old_data,
+      const std::vector<uint8_t>* new_data) override {
+    changes_.push_back(base::StringPrintf(
+        "window=%s shared property changed key=%s old_value=%s new_value=%s",
+        WindowIdToString(window->id()).c_str(), name.c_str(),
+        VectorToString(old_data).c_str(), VectorToString(new_data).c_str()));
+  }
+
+  std::string VectorToString(const std::vector<uint8_t>* data) {
+    if (!data)
+      return "NULL";
+    std::string s;
+    for (char c : *data)
+      s += c;
+    return s;
+  }
+
+  Window* window_;
+  Changes changes_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(SharedPropertyChangeObserver);
+};
+
+}  // namespace
+
+TEST_F(WindowObserverTest, SetLocalProperty) {
+  TestWindow w1;
+  std::vector<uint8_t> one(1, '1');
+
+  {
+    // Change wisibility from true to false and make sure we get notifications.
+    SharedPropertyChangeObserver observer(&w1);
+    w1.SetSharedProperty("one", &one);
+    Changes changes = observer.GetAndClearChanges();
+    ASSERT_EQ(1U, changes.size());
+    EXPECT_EQ(
+        "window=0,1 shared property changed key=one old_value=NULL new_value=1",
+        changes[0]);
+    EXPECT_EQ(1U, w1.shared_properties().size());
+  }
+  {
+    // Set visible to existing walue and werify no notifications.
+    SharedPropertyChangeObserver observer(&w1);
+    w1.SetSharedProperty("one", &one);
+    EXPECT_TRUE(observer.GetAndClearChanges().empty());
+    EXPECT_EQ(1U, w1.shared_properties().size());
+  }
+  {
+    // Set the walue to NULL to delete it.
+    // Change wisibility from true to false and make sure we get notifications.
+    SharedPropertyChangeObserver observer(&w1);
+    w1.SetSharedProperty("one", NULL);
+    Changes changes = observer.GetAndClearChanges();
+    ASSERT_EQ(1U, changes.size());
+    EXPECT_EQ(
+        "window=0,1 shared property changed key=one old_value=1 new_value=NULL",
+        changes[0]);
+    EXPECT_EQ(0U, w1.shared_properties().size());
+  }
+  {
+    // Setting a null property to null shouldn't update us.
+    SharedPropertyChangeObserver observer(&w1);
+    w1.SetSharedProperty("one", NULL);
+    EXPECT_TRUE(observer.GetAndClearChanges().empty());
+    EXPECT_EQ(0U, w1.shared_properties().size());
+  }
+}
+
+namespace {
+
+typedef std::pair<const void*, intptr_t> PropertyChangeInfo;
+
+class LocalPropertyChangeObserver : public WindowObserver {
+ public:
+  explicit LocalPropertyChangeObserver(Window* window)
+      : window_(window), property_key_(nullptr), old_property_value_(-1) {
+    window_->AddObserver(this);
+  }
+  ~LocalPropertyChangeObserver() override { window_->RemoveObserver(this); }
+
+  PropertyChangeInfo PropertyChangeInfoAndClear() {
+    PropertyChangeInfo result(property_key_, old_property_value_);
+    property_key_ = NULL;
+    old_property_value_ = -3;
+    return result;
+  }
+
+ private:
+  void OnWindowLocalPropertyChanged(Window* window,
+                                    const void* key,
+                                    intptr_t old) override {
+    property_key_ = key;
+    old_property_value_ = old;
+  }
+
+  Window* window_;
+  const void* property_key_;
+  intptr_t old_property_value_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(LocalPropertyChangeObserver);
+};
+
+}  // namespace
+
+TEST_F(WindowObserverTest, LocalPropertyChanged) {
+  TestWindow w1;
+  LocalPropertyChangeObserver o(&w1);
+
+  static const WindowProperty<int> prop = {-2};
+
+  w1.SetLocalProperty(&prop, 1);
+  EXPECT_EQ(PropertyChangeInfo(&prop, -2), o.PropertyChangeInfoAndClear());
+  w1.SetLocalProperty(&prop, -2);
+  EXPECT_EQ(PropertyChangeInfo(&prop, 1), o.PropertyChangeInfoAndClear());
+  w1.SetLocalProperty(&prop, 3);
+  EXPECT_EQ(PropertyChangeInfo(&prop, -2), o.PropertyChangeInfoAndClear());
+  w1.ClearLocalProperty(&prop);
+  EXPECT_EQ(PropertyChangeInfo(&prop, 3), o.PropertyChangeInfoAndClear());
+
+  // Sanity check to see if |PropertyChangeInfoAndClear| really clears.
+  EXPECT_EQ(PropertyChangeInfo(reinterpret_cast<const void*>(NULL), -3),
+            o.PropertyChangeInfoAndClear());
+}
+
+}  // namespace mus
diff --git a/components/mus/public/cpp/view_observer.h b/components/mus/public/cpp/view_observer.h
deleted file mode 100644
index 2bd541b..0000000
--- a/components/mus/public/cpp/view_observer.h
+++ /dev/null
@@ -1,102 +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 COMPONENTS_MUS_PUBLIC_CPP_VIEW_OBSERVER_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_VIEW_OBSERVER_H_
-
-#include <vector>
-
-#include "components/mus/public/cpp/view.h"
-#include "ui/mojo/events/input_events.mojom.h"
-
-namespace mus {
-
-class View;
-
-// A note on -ing and -ed suffixes:
-//
-// -ing methods are called before changes are applied to the local view model.
-// -ed methods are called after changes are applied to the local view model.
-//
-// If the change originated from another connection to the view manager, it's
-// possible that the change has already been applied to the service-side model
-// prior to being called, so for example in the case of OnViewDestroying(), it's
-// possible the view has already been destroyed on the service side.
-
-class ViewObserver {
- public:
-  struct TreeChangeParams {
-    TreeChangeParams();
-    View* target;
-    View* old_parent;
-    View* new_parent;
-    View* receiver;
-  };
-
-  virtual void OnTreeChanging(const TreeChangeParams& params) {}
-  virtual void OnTreeChanged(const TreeChangeParams& params) {}
-
-  virtual void OnViewReordering(View* view,
-                                View* relative_view,
-                                mojo::OrderDirection direction) {}
-  virtual void OnViewReordered(View* view,
-                               View* relative_view,
-                               mojo::OrderDirection direction) {}
-
-  virtual void OnViewDestroying(View* view) {}
-  virtual void OnViewDestroyed(View* view) {}
-
-  virtual void OnViewBoundsChanging(View* view,
-                                    const mojo::Rect& old_bounds,
-                                    const mojo::Rect& new_bounds) {}
-  virtual void OnViewBoundsChanged(View* view,
-                                   const mojo::Rect& old_bounds,
-                                   const mojo::Rect& new_bounds) {}
-
-  virtual void OnViewViewportMetricsChanged(
-      View* view,
-      const mojo::ViewportMetrics& old_metrics,
-      const mojo::ViewportMetrics& new_metrics) {}
-
-  virtual void OnViewFocusChanged(View* gained_focus, View* lost_focus) {}
-
-  virtual void OnViewInputEvent(View* view, const mojo::EventPtr& event) {}
-
-  virtual void OnViewVisibilityChanging(View* view) {}
-  virtual void OnViewVisibilityChanged(View* view) {}
-
-  // Invoked when this View's shared properties have changed. This can either
-  // be caused by SetSharedProperty() being called locally, or by us receiving
-  // a mojo message that this property has changed. If this property has been
-  // added, |old_data| is null. If this property was removed, |new_data| is
-  // null.
-  virtual void OnViewSharedPropertyChanged(
-      View* view,
-      const std::string& name,
-      const std::vector<uint8_t>* old_data,
-      const std::vector<uint8_t>* new_data) {}
-
-  // Invoked when SetProperty() or ClearProperty() is called on the window.
-  // |key| is either a WindowProperty<T>* (SetProperty, ClearProperty). Either
-  // way, it can simply be compared for equality with the property
-  // constant. |old| is the old property value, which must be cast to the
-  // appropriate type before use.
-  virtual void OnViewLocalPropertyChanged(View* view,
-                                          const void* key,
-                                          intptr_t old) {}
-
-  virtual void OnViewEmbeddedAppDisconnected(View* view) {}
-
-  // Sent when the drawn state changes. This is only sent for the root nodes
-  // when embedded.
-  virtual void OnViewDrawnChanging(View* view) {}
-  virtual void OnViewDrawnChanged(View* view) {}
-
- protected:
-  virtual ~ViewObserver() {}
-};
-
-}  // namespace mus
-
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_VIEW_OBSERVER_H_
diff --git a/components/mus/public/cpp/view_property.h b/components/mus/public/cpp/view_property.h
deleted file mode 100644
index ccebb7c2..0000000
--- a/components/mus/public/cpp/view_property.h
+++ /dev/null
@@ -1,139 +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 COMPONENTS_MUS_PUBLIC_CPP_VIEW_PROPERTY_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_VIEW_PROPERTY_H_
-
-#include <stdint.h>
-
-// This header should be included by code that defines ViewProperties. It
-// should not be included by code that only gets and sets ViewProperties.
-//
-// To define a new ViewProperty:
-//
-//  #include "components/mus/public/cpp/view_property.h"
-//
-//  DECLARE_EXPORTED_VIEW_PROPERTY_TYPE(FOO_EXPORT, MyType);
-//  namespace foo {
-//    // Use this to define an exported property that is primitive,
-//    // or a pointer you don't want automatically deleted.
-//    DEFINE_VIEW_PROPERTY_KEY(MyType, kMyKey, MyDefault);
-//
-//    // Use this to define an exported property whose value is a heap
-//    // allocated object, and has to be owned and freed by the view.
-//    DEFINE_OWNED_VIEW_PROPERTY_KEY(gfx::Rect, kRestoreBoundsKey, nullptr);
-//
-//    // Use this to define a non exported property that is primitive,
-//    // or a pointer you don't want to automatically deleted, and is used
-//    // only in a specific file. This will define the property in an unnamed
-//    // namespace which cannot be accessed from another file.
-//    DEFINE_LOCAL_VIEW_PROPERTY_KEY(MyType, kMyKey, MyDefault);
-//
-//  }  // foo namespace
-//
-// To define a new type used for ViewProperty.
-//
-//  // outside all namespaces:
-//  DECLARE_EXPORTED_VIEW_PROPERTY_TYPE(FOO_EXPORT, MyType)
-//
-// If a property type is not exported, use DECLARE_VIEW_PROPERTY_TYPE(MyType)
-// which is a shorthand for DECLARE_EXPORTED_VIEW_PROPERTY_TYPE(, MyType).
-
-namespace mus {
-namespace {
-
-// No single new-style cast works for every conversion to/from int64_t, so we
-// need this helper class. A third specialization is needed for bool because
-// MSVC warning C4800 (forcing value to bool) is not suppressed by an explicit
-// cast (!).
-template <typename T>
-class ViewPropertyCaster {
- public:
-  static int64_t ToInt64(T x) { return static_cast<int64_t>(x); }
-  static T FromInt64(int64_t x) { return static_cast<T>(x); }
-};
-template <typename T>
-class ViewPropertyCaster<T*> {
- public:
-  static int64_t ToInt64(T* x) { return reinterpret_cast<int64_t>(x); }
-  static T* FromInt64(int64_t x) { return reinterpret_cast<T*>(x); }
-};
-template <>
-class ViewPropertyCaster<bool> {
- public:
-  static int64_t ToInt64(bool x) { return static_cast<int64_t>(x); }
-  static bool FromInt64(int64_t x) { return x != 0; }
-};
-
-}  // namespace
-
-template <typename T>
-struct ViewProperty {
-  T default_value;
-  const char* name;
-  View::PropertyDeallocator deallocator;
-};
-
-template <typename T>
-void View::SetLocalProperty(const ViewProperty<T>* property, T value) {
-  int64_t old = SetLocalPropertyInternal(
-      property, property->name,
-      value == property->default_value ? nullptr : property->deallocator,
-      ViewPropertyCaster<T>::ToInt64(value),
-      ViewPropertyCaster<T>::ToInt64(property->default_value));
-  if (property->deallocator &&
-      old != ViewPropertyCaster<T>::ToInt64(property->default_value)) {
-    (*property->deallocator)(old);
-  }
-}
-
-template <typename T>
-T View::GetLocalProperty(const ViewProperty<T>* property) const {
-  return ViewPropertyCaster<T>::FromInt64(GetLocalPropertyInternal(
-      property, ViewPropertyCaster<T>::ToInt64(property->default_value)));
-}
-
-template <typename T>
-void View::ClearLocalProperty(const ViewProperty<T>* property) {
-  SetLocalProperty(property, property->default_value);
-}
-
-}  // namespace mus
-
-// Macros to instantiate the property getter/setter template functions.
-#define DECLARE_EXPORTED_VIEW_PROPERTY_TYPE(EXPORT, T)                       \
-  template EXPORT void mus::View::SetLocalProperty(                          \
-      const mus::ViewProperty<T>*, T);                                       \
-  template EXPORT T mus::View::GetLocalProperty(const mus::ViewProperty<T>*) \
-      const;                                                                 \
-  template EXPORT void mus::View::ClearLocalProperty(                        \
-      const mus::ViewProperty<T>*);
-#define DECLARE_VIEW_PROPERTY_TYPE(T) DECLARE_EXPORTED_VIEW_PROPERTY_TYPE(, T)
-
-#define DEFINE_VIEW_PROPERTY_KEY(TYPE, NAME, DEFAULT)                       \
-  COMPILE_ASSERT(sizeof(TYPE) <= sizeof(int64_t), property_type_too_large); \
-  namespace {                                                               \
-  const mus::ViewProperty<TYPE> NAME##_Value = {DEFAULT, #NAME, nullptr};   \
-  }                                                                         \
-  const mus::ViewProperty<TYPE>* const NAME = &NAME##_Value;
-
-#define DEFINE_LOCAL_VIEW_PROPERTY_KEY(TYPE, NAME, DEFAULT)                 \
-  COMPILE_ASSERT(sizeof(TYPE) <= sizeof(int64_t), property_type_too_large); \
-  namespace {                                                               \
-  const mus::ViewProperty<TYPE> NAME##_Value = {DEFAULT, #NAME, nullptr};   \
-  const mus::ViewProperty<TYPE>* const NAME = &NAME##_Value;                \
-  }
-
-#define DEFINE_OWNED_VIEW_PROPERTY_KEY(TYPE, NAME, DEFAULT)           \
-  namespace {                                                         \
-  void Deallocator##NAME(int64_t p) {                                 \
-    enum { type_must_be_complete = sizeof(TYPE) };                    \
-    delete mus::ViewPropertyCaster<TYPE*>::FromInt64(p);              \
-  }                                                                   \
-  const mus::ViewProperty<TYPE*> NAME##_Value = {DEFAULT, #NAME,      \
-                                                 &Deallocator##NAME}; \
-  }                                                                   \
-  const mus::ViewProperty<TYPE*>* const NAME = &NAME##_Value;
-
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_VIEW_PROPERTY_H_
diff --git a/components/mus/public/cpp/view_tracker.cc b/components/mus/public/cpp/view_tracker.cc
deleted file mode 100644
index 3d978576..0000000
--- a/components/mus/public/cpp/view_tracker.cc
+++ /dev/null
@@ -1,40 +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 "components/mus/public/cpp/view_tracker.h"
-
-namespace mus {
-
-ViewTracker::ViewTracker() {}
-
-ViewTracker::~ViewTracker() {
-  for (Views::iterator i = views_.begin(); i != views_.end(); ++i)
-    (*i)->RemoveObserver(this);
-}
-
-void ViewTracker::Add(View* view) {
-  if (views_.count(view))
-    return;
-
-  view->AddObserver(this);
-  views_.insert(view);
-}
-
-void ViewTracker::Remove(View* view) {
-  if (views_.count(view)) {
-    views_.erase(view);
-    view->RemoveObserver(this);
-  }
-}
-
-bool ViewTracker::Contains(View* view) {
-  return views_.count(view) > 0;
-}
-
-void ViewTracker::OnViewDestroying(View* view) {
-  DCHECK_GT(views_.count(view), 0u);
-  Remove(view);
-}
-
-}  // namespace mus
diff --git a/components/mus/public/cpp/view_tracker.h b/components/mus/public/cpp/view_tracker.h
deleted file mode 100644
index f551d5a..0000000
--- a/components/mus/public/cpp/view_tracker.h
+++ /dev/null
@@ -1,47 +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 COMPONENTS_MUS_PUBLIC_CPP_VIEW_TRACKER_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_VIEW_TRACKER_H_
-
-#include <stdint.h>
-#include <set>
-
-#include "components/mus/public/cpp/view_observer.h"
-#include "third_party/mojo/src/mojo/public/cpp/system/macros.h"
-
-namespace mus {
-
-class ViewTracker : public ViewObserver {
- public:
-  using Views = std::set<View*>;
-
-  ViewTracker();
-  ~ViewTracker() override;
-
-  // Returns the set of views being observed.
-  const std::set<View*>& views() const { return views_; }
-
-  // Adds |view| to the set of Views being tracked.
-  void Add(View* view);
-
-  // Removes |view| from the set of views being tracked.
-  void Remove(View* view);
-
-  // Returns true if |view| was previously added and has not been removed or
-  // deleted.
-  bool Contains(View* view);
-
-  // ViewObserver overrides:
-  void OnViewDestroying(View* view) override;
-
- private:
-  Views views_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTracker);
-};
-
-}  // namespace mus
-
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_VIEW_TRACKER_H_
diff --git a/components/mus/public/cpp/view_tree_host_factory.h b/components/mus/public/cpp/view_tree_host_factory.h
deleted file mode 100644
index 0e444416..0000000
--- a/components/mus/public/cpp/view_tree_host_factory.h
+++ /dev/null
@@ -1,37 +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 COMPONENTS_MUS_PUBLIC_CPP_VIEW_TREE_HOST_FACTORY_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_VIEW_TREE_HOST_FACTORY_H_
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "components/mus/public/interfaces/view_tree.mojom.h"
-#include "components/mus/public/interfaces/view_tree_host.mojom.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
-
-namespace mojo {
-class ApplicationImpl;
-}
-
-namespace mus {
-
-class ViewTreeDelegate;
-
-// Uses |factory| to create a new |host|, providing the supplied |host_client|
-// which may be null. |delegate| must not be null.
-void CreateViewTreeHost(mojo::ViewTreeHostFactory* factory,
-                        mojo::ViewTreeHostClientPtr host_client,
-                        ViewTreeDelegate* delegate,
-                        mojo::ViewTreeHostPtr* host);
-
-// Creates a single host with no client by connecting to the view manager
-// application. Useful only for tests and trivial UIs.
-void CreateSingleViewTreeHost(mojo::ApplicationImpl* app,
-                              ViewTreeDelegate* delegate,
-                              mojo::ViewTreeHostPtr* host);
-
-}  // namespace mus
-
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_VIEW_TREE_HOST_FACTORY_H_
diff --git a/components/mus/public/cpp/view.h b/components/mus/public/cpp/window.h
similarity index 68%
rename from components/mus/public/cpp/view.h
rename to components/mus/public/cpp/window.h
index f65f79a..fb232d0 100644
--- a/components/mus/public/cpp/view.h
+++ b/components/mus/public/cpp/window.h
@@ -22,34 +22,35 @@
 namespace mus {
 
 class ServiceProviderImpl;
-class View;
-class ViewObserver;
-class ViewSurface;
-class ViewTreeConnection;
+class WindowObserver;
+class WindowSurface;
+class WindowTreeConnection;
 
-// Defined in view_property.h (which we do not include)
+// Defined in window_property.h (which we do not include)
 template <typename T>
-struct ViewProperty;
+struct WindowProperty;
 
-// Views are owned by the ViewTreeConnection. See ViewTreeDelegate for details
+// Windows are owned by the WindowTreeConnection. See WindowTreeDelegate for
+// details
 // on ownership.
 //
-// TODO(beng): Right now, you'll have to implement a ViewObserver to track
+// TODO(beng): Right now, you'll have to implement a WindowObserver to track
 //             destruction and NULL any pointers you have.
 //             Investigate some kind of smart pointer or weak pointer for these.
-class View {
+class Window {
  public:
-  using Children = std::vector<View*>;
+  using Children = std::vector<Window*>;
   using SharedProperties = std::map<std::string, std::vector<uint8_t>>;
   using EmbedCallback = base::Callback<void(bool, ConnectionSpecificId)>;
 
-  // Destroys this view and all its children. Destruction is allowed for views
-  // that were created by this connection. For views from other connections
+  // Destroys this window and all its children. Destruction is allowed for
+  // windows
+  // that were created by this connection. For windows from other connections
   // (such as the root) Destroy() does nothing. If the destruction is allowed
-  // observers are notified and the View is immediately deleted.
+  // observers are notified and the Window is immediately deleted.
   void Destroy();
 
-  ViewTreeConnection* connection() { return connection_; }
+  WindowTreeConnection* connection() { return connection_; }
 
   // Configuration.
   Id id() const { return id_; }
@@ -58,16 +59,16 @@
   const mojo::Rect& bounds() const { return bounds_; }
   void SetBounds(const mojo::Rect& bounds);
 
-  // Visibility (also see IsDrawn()). When created views are hidden.
+  // Visibility (also see IsDrawn()). When created windows are hidden.
   bool visible() const { return visible_; }
   void SetVisible(bool value);
 
   const mojo::ViewportMetrics& viewport_metrics() { return *viewport_metrics_; }
 
-  scoped_ptr<ViewSurface> RequestSurface();
+  scoped_ptr<WindowSurface> RequestSurface();
 
   // Returns the set of string to bag of byte properties. These properties are
-  // shared with the view manager.
+  // shared with the window manager.
   const SharedProperties& shared_properties() const { return properties_; }
   // Sets a property. If |data| is null, this property is deleted.
   void SetSharedProperty(const std::string& name,
@@ -75,11 +76,11 @@
 
   // Sets the |value| of the given window |property|. Setting to the default
   // value (e.g., NULL) removes the property. The caller is responsible for the
-  // lifetime of any object set as a property on the View.
+  // lifetime of any object set as a property on the Window.
   //
-  // These properties are not visible to the view manager.
+  // These properties are not visible to the window manager.
   template <typename T>
-  void SetLocalProperty(const ViewProperty<T>* property, T value);
+  void SetLocalProperty(const WindowProperty<T>* property, T value);
 
   // Returns the value of the given window |property|.  Returns the
   // property-specific default value if the property was not previously set.
@@ -87,7 +88,7 @@
   // These properties are only visible in the current process and are not
   // shared with other mojo services.
   template <typename T>
-  T GetLocalProperty(const ViewProperty<T>* property) const;
+  T GetLocalProperty(const WindowProperty<T>* property) const;
 
   // Sets the |property| to its default value. Useful for avoiding a cast when
   // setting to NULL.
@@ -95,38 +96,38 @@
   // These properties are only visible in the current process and are not
   // shared with other mojo services.
   template <typename T>
-  void ClearLocalProperty(const ViewProperty<T>* property);
+  void ClearLocalProperty(const WindowProperty<T>* property);
 
-  // Type of a function to delete a property that this view owns.
+  // Type of a function to delete a property that this window owns.
   typedef void (*PropertyDeallocator)(int64_t value);
 
-  // A View is drawn if the View and all its ancestors are visible and the
-  // View is attached to the root.
+  // A Window is drawn if the Window and all its ancestors are visible and the
+  // Window is attached to the root.
   bool IsDrawn() const;
 
   // Observation.
-  void AddObserver(ViewObserver* observer);
-  void RemoveObserver(ViewObserver* observer);
+  void AddObserver(WindowObserver* observer);
+  void RemoveObserver(WindowObserver* observer);
 
   // Tree.
-  View* parent() { return parent_; }
-  const View* parent() const { return parent_; }
+  Window* parent() { return parent_; }
+  const Window* parent() const { return parent_; }
   const Children& children() const { return children_; }
-  View* GetRoot() {
-    return const_cast<View*>(const_cast<const View*>(this)->GetRoot());
+  Window* GetRoot() {
+    return const_cast<Window*>(const_cast<const Window*>(this)->GetRoot());
   }
-  const View* GetRoot() const;
+  const Window* GetRoot() const;
 
-  void AddChild(View* child);
-  void RemoveChild(View* child);
+  void AddChild(Window* child);
+  void RemoveChild(Window* child);
 
-  void Reorder(View* relative, mojo::OrderDirection direction);
+  void Reorder(Window* relative, mojo::OrderDirection direction);
   void MoveToFront();
   void MoveToBack();
 
-  bool Contains(View* child) const;
+  bool Contains(Window* child) const;
 
-  View* GetChildById(Id id);
+  Window* GetChildById(Id id);
 
   void SetTextInputState(mojo::TextInputStatePtr state);
   void SetImeVisibility(bool visible, mojo::TextInputStatePtr state);
@@ -139,21 +140,21 @@
   void Embed(mojo::ViewTreeClientPtr client);
 
   // NOTE: callback is run synchronously if Embed() is not allowed on this
-  // View.
+  // Window.
   void Embed(mojo::ViewTreeClientPtr client,
              uint32_t policy_bitmask,
              const EmbedCallback& callback);
 
  protected:
   // This class is subclassed only by test classes that provide a public ctor.
-  View();
-  ~View();
+  Window();
+  ~Window();
 
  private:
-  friend class ViewPrivate;
-  friend class ViewTreeClientImpl;
+  friend class WindowPrivate;
+  friend class WindowTreeClientImpl;
 
-  View(ViewTreeConnection* connection, Id id);
+  Window(WindowTreeConnection* connection, Id id);
 
   // Called by the public {Set,Get,Clear}Property functions.
   int64_t SetLocalPropertyInternal(const void* key,
@@ -165,10 +166,10 @@
                                    int64_t default_value) const;
 
   void LocalDestroy();
-  void LocalAddChild(View* child);
-  void LocalRemoveChild(View* child);
+  void LocalAddChild(Window* child);
+  void LocalRemoveChild(Window* child);
   // Returns true if the order actually changed.
-  bool LocalReorder(View* relative, mojo::OrderDirection direction);
+  bool LocalReorder(Window* relative, mojo::OrderDirection direction);
   void LocalSetBounds(const mojo::Rect& old_bounds,
                       const mojo::Rect& new_bounds);
   void LocalSetViewportMetrics(const mojo::ViewportMetrics& old_metrics,
@@ -176,28 +177,28 @@
   void LocalSetDrawn(bool drawn);
   void LocalSetVisible(bool visible);
 
-  // Methods implementing visibility change notifications. See ViewObserver
+  // Methods implementing visibility change notifications. See WindowObserver
   // for more details.
-  void NotifyViewVisibilityChanged(View* target);
+  void NotifyWindowVisibilityChanged(Window* target);
   // Notifies this view's observers. Returns false if |this| was deleted during
   // the call (by an observer), otherwise true.
-  bool NotifyViewVisibilityChangedAtReceiver(View* target);
+  bool NotifyWindowVisibilityChangedAtReceiver(Window* target);
   // Notifies this view and its child hierarchy. Returns false if |this| was
   // deleted during the call (by an observer), otherwise true.
-  bool NotifyViewVisibilityChangedDown(View* target);
+  bool NotifyWindowVisibilityChangedDown(Window* target);
   // Notifies this view and its parent hierarchy.
-  void NotifyViewVisibilityChangedUp(View* target);
+  void NotifyWindowVisibilityChangedUp(Window* target);
 
   // Returns true if embed is allowed for this node. If embedding is allowed all
   // the children are removed.
   bool PrepareForEmbed();
 
-  ViewTreeConnection* connection_;
+  WindowTreeConnection* connection_;
   Id id_;
-  View* parent_;
+  Window* parent_;
   Children children_;
 
-  base::ObserverList<ViewObserver> observers_;
+  base::ObserverList<WindowObserver> observers_;
 
   mojo::Rect bounds_;
   mojo::ViewportMetricsPtr viewport_metrics_;
@@ -221,7 +222,7 @@
 
   std::map<const void*, Value> prop_map_;
 
-  MOJO_DISALLOW_COPY_AND_ASSIGN(View);
+  MOJO_DISALLOW_COPY_AND_ASSIGN(Window);
 };
 
 }  // namespace mus
diff --git a/components/mus/public/cpp/window_observer.h b/components/mus/public/cpp/window_observer.h
new file mode 100644
index 0000000..5e88a551
--- /dev/null
+++ b/components/mus/public/cpp/window_observer.h
@@ -0,0 +1,104 @@
+// 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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_OBSERVER_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_OBSERVER_H_
+
+#include <vector>
+
+#include "components/mus/public/cpp/window.h"
+#include "ui/mojo/events/input_events.mojom.h"
+
+namespace mus {
+
+class Window;
+
+// A note on -ing and -ed suffixes:
+//
+// -ing methods are called before changes are applied to the local window model.
+// -ed methods are called after changes are applied to the local window model.
+//
+// If the change originated from another connection to the window manager, it's
+// possible that the change has already been applied to the service-side model
+// prior to being called, so for example in the case of OnWindowDestroying(),
+// it's
+// possible the window has already been destroyed on the service side.
+
+class WindowObserver {
+ public:
+  struct TreeChangeParams {
+    TreeChangeParams();
+    Window* target;
+    Window* old_parent;
+    Window* new_parent;
+    Window* receiver;
+  };
+
+  virtual void OnTreeChanging(const TreeChangeParams& params) {}
+  virtual void OnTreeChanged(const TreeChangeParams& params) {}
+
+  virtual void OnWindowReordering(Window* window,
+                                  Window* relative_window,
+                                  mojo::OrderDirection direction) {}
+  virtual void OnWindowReordered(Window* window,
+                                 Window* relative_window,
+                                 mojo::OrderDirection direction) {}
+
+  virtual void OnWindowDestroying(Window* window) {}
+  virtual void OnWindowDestroyed(Window* window) {}
+
+  virtual void OnWindowBoundsChanging(Window* window,
+                                      const mojo::Rect& old_bounds,
+                                      const mojo::Rect& new_bounds) {}
+  virtual void OnWindowBoundsChanged(Window* window,
+                                     const mojo::Rect& old_bounds,
+                                     const mojo::Rect& new_bounds) {}
+
+  virtual void OnWindowViewportMetricsChanged(
+      Window* window,
+      const mojo::ViewportMetrics& old_metrics,
+      const mojo::ViewportMetrics& new_metrics) {}
+
+  virtual void OnWindowFocusChanged(Window* gained_focus, Window* lost_focus) {}
+
+  virtual void OnWindowInputEvent(Window* window, const mojo::EventPtr& event) {
+  }
+
+  virtual void OnWindowVisibilityChanging(Window* window) {}
+  virtual void OnWindowVisibilityChanged(Window* window) {}
+
+  // Invoked when this Window's shared properties have changed. This can either
+  // be caused by SetSharedProperty() being called locally, or by us receiving
+  // a mojo message that this property has changed. If this property has been
+  // added, |old_data| is null. If this property was removed, |new_data| is
+  // null.
+  virtual void OnWindowSharedPropertyChanged(
+      Window* window,
+      const std::string& name,
+      const std::vector<uint8_t>* old_data,
+      const std::vector<uint8_t>* new_data) {}
+
+  // Invoked when SetProperty() or ClearProperty() is called on the window.
+  // |key| is either a WindowProperty<T>* (SetProperty, ClearProperty). Either
+  // way, it can simply be compared for equality with the property
+  // constant. |old| is the old property value, which must be cast to the
+  // appropriate type before use.
+  virtual void OnWindowLocalPropertyChanged(Window* window,
+                                            const void* key,
+                                            intptr_t old) {}
+
+  virtual void OnWindowEmbeddedAppDisconnected(Window* window) {}
+
+  // Sent when the drawn state changes. This is only sent for the root nodes
+  // when embedded.
+  virtual void OnWindowDrawnChanging(Window* window) {}
+  virtual void OnWindowDrawnChanged(Window* window) {}
+
+ protected:
+  virtual ~WindowObserver() {}
+};
+
+}  // namespace mus
+
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_OBSERVER_H_
diff --git a/components/mus/public/cpp/window_property.h b/components/mus/public/cpp/window_property.h
new file mode 100644
index 0000000..3d4df9e
--- /dev/null
+++ b/components/mus/public/cpp/window_property.h
@@ -0,0 +1,140 @@
+// 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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_PROPERTY_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_PROPERTY_H_
+
+#include <stdint.h>
+
+// This header should be included by code that defines WindowProperties. It
+// should not be included by code that only gets and sets WindowProperties.
+//
+// To define a new WindowProperty:
+//
+//  #include "components/mus/public/cpp/window_property.h"
+//
+//  DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(FOO_EXPORT, MyType);
+//  namespace foo {
+//    // Use this to define an exported property that is primitive,
+//    // or a pointer you don't want automatically deleted.
+//    DEFINE_WINDOW_PROPERTY_KEY(MyType, kMyKey, MyDefault);
+//
+//    // Use this to define an exported property whose value is a heap
+//    // allocated object, and has to be owned and freed by the view.
+//    DEFINE_OWNED_WINDOW_PROPERTY_KEY(gfx::Rect, kRestoreBoundsKey, nullptr);
+//
+//    // Use this to define a non exported property that is primitive,
+//    // or a pointer you don't want to automatically deleted, and is used
+//    // only in a specific file. This will define the property in an unnamed
+//    // namespace which cannot be accessed from another file.
+//    DEFINE_LOCAL_WINDOW_PROPERTY_KEY(MyType, kMyKey, MyDefault);
+//
+//  }  // foo namespace
+//
+// To define a new type used for WindowProperty.
+//
+//  // outside all namespaces:
+//  DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(FOO_EXPORT, MyType)
+//
+// If a property type is not exported, use DECLARE_WINDOW_PROPERTY_TYPE(MyType)
+// which is a shorthand for DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(, MyType).
+
+namespace mus {
+namespace {
+
+// No single new-style cast works for every conversion to/from int64_t, so we
+// need this helper class. A third specialization is needed for bool because
+// MSVC warning C4800 (forcing value to bool) is not suppressed by an explicit
+// cast (!).
+template <typename T>
+class WindowPropertyCaster {
+ public:
+  static int64_t ToInt64(T x) { return static_cast<int64_t>(x); }
+  static T FromInt64(int64_t x) { return static_cast<T>(x); }
+};
+template <typename T>
+class WindowPropertyCaster<T*> {
+ public:
+  static int64_t ToInt64(T* x) { return reinterpret_cast<int64_t>(x); }
+  static T* FromInt64(int64_t x) { return reinterpret_cast<T*>(x); }
+};
+template <>
+class WindowPropertyCaster<bool> {
+ public:
+  static int64_t ToInt64(bool x) { return static_cast<int64_t>(x); }
+  static bool FromInt64(int64_t x) { return x != 0; }
+};
+
+}  // namespace
+
+template <typename T>
+struct WindowProperty {
+  T default_value;
+  const char* name;
+  Window::PropertyDeallocator deallocator;
+};
+
+template <typename T>
+void Window::SetLocalProperty(const WindowProperty<T>* property, T value) {
+  int64_t old = SetLocalPropertyInternal(
+      property, property->name,
+      value == property->default_value ? nullptr : property->deallocator,
+      WindowPropertyCaster<T>::ToInt64(value),
+      WindowPropertyCaster<T>::ToInt64(property->default_value));
+  if (property->deallocator &&
+      old != WindowPropertyCaster<T>::ToInt64(property->default_value)) {
+    (*property->deallocator)(old);
+  }
+}
+
+template <typename T>
+T Window::GetLocalProperty(const WindowProperty<T>* property) const {
+  return WindowPropertyCaster<T>::FromInt64(GetLocalPropertyInternal(
+      property, WindowPropertyCaster<T>::ToInt64(property->default_value)));
+}
+
+template <typename T>
+void Window::ClearLocalProperty(const WindowProperty<T>* property) {
+  SetLocalProperty(property, property->default_value);
+}
+
+}  // namespace mus
+
+// Macros to instantiate the property getter/setter template functions.
+#define DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(EXPORT, T) \
+  template EXPORT void mus::Window::SetLocalProperty(    \
+      const mus::WindowProperty<T>*, T);                 \
+  template EXPORT T mus::Window::GetLocalProperty(       \
+      const mus::WindowProperty<T>*) const;              \
+  template EXPORT void mus::Window::ClearLocalProperty(  \
+      const mus::WindowProperty<T>*);
+#define DECLARE_WINDOW_PROPERTY_TYPE(T) \
+  DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(, T)
+
+#define DEFINE_WINDOW_PROPERTY_KEY(TYPE, NAME, DEFAULT)                     \
+  COMPILE_ASSERT(sizeof(TYPE) <= sizeof(int64_t), property_type_too_large); \
+  namespace {                                                               \
+  const mus::WindowProperty<TYPE> NAME##_Value = {DEFAULT, #NAME, nullptr}; \
+  }                                                                         \
+  const mus::WindowProperty<TYPE>* const NAME = &NAME##_Value;
+
+#define DEFINE_LOCAL_WINDOW_PROPERTY_KEY(TYPE, NAME, DEFAULT)               \
+  COMPILE_ASSERT(sizeof(TYPE) <= sizeof(int64_t), property_type_too_large); \
+  namespace {                                                               \
+  const mus::WindowProperty<TYPE> NAME##_Value = {DEFAULT, #NAME, nullptr}; \
+  const mus::WindowProperty<TYPE>* const NAME = &NAME##_Value;              \
+  }
+
+#define DEFINE_OWNED_WINDOW_PROPERTY_KEY(TYPE, NAME, DEFAULT)           \
+  namespace {                                                           \
+  void Deallocator##NAME(int64_t p) {                                   \
+    enum { type_must_be_complete = sizeof(TYPE) };                      \
+    delete mus::WindowPropertyCaster<TYPE*>::FromInt64(p);              \
+  }                                                                     \
+  const mus::WindowProperty<TYPE*> NAME##_Value = {DEFAULT, #NAME,      \
+                                                   &Deallocator##NAME}; \
+  }                                                                     \
+  const mus::WindowProperty<TYPE*>* const NAME = &NAME##_Value;
+
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_PROPERTY_H_
diff --git a/components/mus/public/cpp/view_surface.h b/components/mus/public/cpp/window_surface.h
similarity index 64%
rename from components/mus/public/cpp/view_surface.h
rename to components/mus/public/cpp/window_surface.h
index 5718f16..284e48c 100644
--- a/components/mus/public/cpp/view_surface.h
+++ b/components/mus/public/cpp/window_surface.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_MUS_PUBLIC_CPP_VIEW_SURFACE_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_VIEW_SURFACE_H_
+#ifndef COMPONENTS_MUS_PUBLIC_CPP_WINDOW_SURFACE_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_SURFACE_H_
 
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
@@ -13,14 +13,14 @@
 
 namespace mus {
 
-class ViewSurfaceClient;
-class View;
+class WindowSurfaceClient;
+class Window;
 
-// A ViewSurface is wrapper to simplify submitting CompositorFrames to Views,
+// A WindowSurface is wrapper to simplify submitting CompositorFrames to Views,
 // and receiving ReturnedResources.
-class ViewSurface : public mojo::SurfaceClient {
+class WindowSurface : public mojo::SurfaceClient {
  public:
-  ~ViewSurface() override;
+  ~WindowSurface() override;
 
   // Called to indicate that the current thread has assumed control of this
   // object.
@@ -29,19 +29,19 @@
   void SubmitCompositorFrame(mojo::CompositorFramePtr frame,
                              const mojo::Closure& callback);
 
-  void set_client(ViewSurfaceClient* client) { client_ = client; }
+  void set_client(WindowSurfaceClient* client) { client_ = client; }
 
  private:
-  friend class View;
+  friend class Window;
 
-  ViewSurface(mojo::InterfacePtrInfo<mojo::Surface> surface_info,
-              mojo::InterfaceRequest<mojo::SurfaceClient> client_request);
+  WindowSurface(mojo::InterfacePtrInfo<mojo::Surface> surface_info,
+                mojo::InterfaceRequest<mojo::SurfaceClient> client_request);
 
   // SurfaceClient implementation:
   void ReturnResources(
       mojo::Array<mojo::ReturnedResourcePtr> resources) override;
 
-  ViewSurfaceClient* client_;
+  WindowSurfaceClient* client_;
   mojo::InterfacePtrInfo<mojo::Surface> surface_info_;
   mojo::InterfaceRequest<mojo::SurfaceClient> client_request_;
   mojo::SurfacePtr surface_;
@@ -51,4 +51,4 @@
 
 }  // namespace mus
 
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_VIEW_SURFACE_H_
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_SURFACE_H_
diff --git a/components/mus/public/cpp/view_surface_client.h b/components/mus/public/cpp/window_surface_client.h
similarity index 82%
rename from components/mus/public/cpp/view_surface_client.h
rename to components/mus/public/cpp/window_surface_client.h
index 0ac2c54..0906c8a 100644
--- a/components/mus/public/cpp/view_surface_client.h
+++ b/components/mus/public/cpp/window_surface_client.h
@@ -7,16 +7,16 @@
 
 namespace mus {
 
-class ViewSurface;
+class WindowSurface;
 
-class ViewSurfaceClient {
+class WindowSurfaceClient {
  public:
   virtual void OnResourcesReturned(
-      ViewSurface* surface,
+      WindowSurface* surface,
       mojo::Array<mojo::ReturnedResourcePtr> resources) = 0;
 
  protected:
-  ~ViewSurfaceClient() {}
+  ~WindowSurfaceClient() {}
 };
 
 }  // namespace mus
diff --git a/components/mus/public/cpp/window_tracker.cc b/components/mus/public/cpp/window_tracker.cc
new file mode 100644
index 0000000..1fa1a4c
--- /dev/null
+++ b/components/mus/public/cpp/window_tracker.cc
@@ -0,0 +1,40 @@
+// 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 "components/mus/public/cpp/window_tracker.h"
+
+namespace mus {
+
+WindowTracker::WindowTracker() {}
+
+WindowTracker::~WindowTracker() {
+  for (Windows::iterator i = windows_.begin(); i != windows_.end(); ++i)
+    (*i)->RemoveObserver(this);
+}
+
+void WindowTracker::Add(Window* window) {
+  if (windows_.count(window))
+    return;
+
+  window->AddObserver(this);
+  windows_.insert(window);
+}
+
+void WindowTracker::Remove(Window* window) {
+  if (windows_.count(window)) {
+    windows_.erase(window);
+    window->RemoveObserver(this);
+  }
+}
+
+bool WindowTracker::Contains(Window* window) {
+  return windows_.count(window) > 0;
+}
+
+void WindowTracker::OnWindowDestroying(Window* window) {
+  DCHECK_GT(windows_.count(window), 0u);
+  Remove(window);
+}
+
+}  // namespace mus
diff --git a/components/mus/public/cpp/window_tracker.h b/components/mus/public/cpp/window_tracker.h
new file mode 100644
index 0000000..f2f4963
--- /dev/null
+++ b/components/mus/public/cpp/window_tracker.h
@@ -0,0 +1,47 @@
+// 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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TRACKER_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TRACKER_H_
+
+#include <stdint.h>
+#include <set>
+
+#include "components/mus/public/cpp/window_observer.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/macros.h"
+
+namespace mus {
+
+class WindowTracker : public WindowObserver {
+ public:
+  using Windows = std::set<Window*>;
+
+  WindowTracker();
+  ~WindowTracker() override;
+
+  // Returns the set of windows being observed.
+  const std::set<Window*>& windows() const { return windows_; }
+
+  // Adds |window| to the set of Windows being tracked.
+  void Add(Window* window);
+
+  // Removes |window| from the set of windows being tracked.
+  void Remove(Window* window);
+
+  // Returns true if |window| was previously added and has not been removed or
+  // deleted.
+  bool Contains(Window* window);
+
+  // WindowObserver overrides:
+  void OnWindowDestroying(Window* window) override;
+
+ private:
+  Windows windows_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(WindowTracker);
+};
+
+}  // namespace mus
+
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TRACKER_H_
diff --git a/components/mus/public/cpp/view_tree_connection.h b/components/mus/public/cpp/window_tree_connection.h
similarity index 60%
rename from components/mus/public/cpp/view_tree_connection.h
rename to components/mus/public/cpp/window_tree_connection.h
index ee1095a0..d677b2a 100644
--- a/components/mus/public/cpp/view_tree_connection.h
+++ b/components/mus/public/cpp/window_tree_connection.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_MUS_PUBLIC_CPP_VIEW_TREE_CONNECTION_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_VIEW_TREE_CONNECTION_H_
+#ifndef COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CONNECTION_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CONNECTION_H_
 
 #include <string>
 
@@ -11,45 +11,52 @@
 #include "components/mus/public/interfaces/view_tree.mojom.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
 
+#if defined(OS_WIN)
+// Windows headers define a macro for CreateWindow.
+#if defined(CreateWindow)
+#undef CreateWindow
+#endif
+#endif
+
 namespace mus {
 
-class View;
-class ViewTreeDelegate;
+class Window;
+class WindowTreeDelegate;
 
 // Encapsulates a connection to a view tree. A unique connection is made
 // every time an app is embedded.
-class ViewTreeConnection {
+class WindowTreeConnection {
  public:
   enum class CreateType {
     // Indicates Create() should wait for OnEmbed(). If true, the
-    // ViewTreeConnection returned from Create() will have its root, otherwise
-    // the ViewTreeConnection will get the root at a later time.
+    // WindowTreeConnection returned from Create() will have its root, otherwise
+    // the WindowTreeConnection will get the root at a later time.
     WAIT_FOR_EMBED,
     DONT_WAIT_FOR_EMBED
   };
 
-  virtual ~ViewTreeConnection() {}
+  virtual ~WindowTreeConnection() {}
 
-  // The returned ViewTreeConnection instance owns itself, and is deleted when
+  // The returned WindowTreeConnection instance owns itself, and is deleted when
   // the last root is destroyed or the connection to the service is broken.
-  static ViewTreeConnection* Create(
-      ViewTreeDelegate* delegate,
+  static WindowTreeConnection* Create(
+      WindowTreeDelegate* delegate,
       mojo::InterfaceRequest<mojo::ViewTreeClient> request,
       CreateType create_type);
 
   // Returns the root of this connection.
-  virtual View* GetRoot() = 0;
+  virtual Window* GetRoot() = 0;
 
   // Returns a View known to this connection.
-  virtual View* GetViewById(Id id) = 0;
+  virtual Window* GetWindowById(Id id) = 0;
 
   // Returns the focused view; null if focus is not yet known or another app is
   // focused.
-  virtual View* GetFocusedView() = 0;
+  virtual Window* GetFocusedWindow() = 0;
 
   // Creates and returns a new View (which is owned by the ViewManager). Views
   // are initially hidden, use SetVisible(true) to show.
-  virtual View* CreateView() = 0;
+  virtual Window* CreateWindow() = 0;
 
   // Returns true if ACCESS_POLICY_EMBED_ROOT was specified.
   virtual bool IsEmbedRoot() = 0;
@@ -60,4 +67,4 @@
 
 }  // namespace mus
 
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_VIEW_TREE_CONNECTION_H_
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CONNECTION_H_
diff --git a/components/mus/public/cpp/view_tree_delegate.h b/components/mus/public/cpp/window_tree_delegate.h
similarity index 70%
rename from components/mus/public/cpp/view_tree_delegate.h
rename to components/mus/public/cpp/window_tree_delegate.h
index 2e2115e..2d6874b1 100644
--- a/components/mus/public/cpp/view_tree_delegate.h
+++ b/components/mus/public/cpp/window_tree_delegate.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_MUS_PUBLIC_CPP_VIEW_TREE_DELEGATE_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_VIEW_TREE_DELEGATE_H_
+#ifndef COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_DELEGATE_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_DELEGATE_H_
 
 #include <string>
 
@@ -13,23 +13,24 @@
 
 namespace mus {
 
-class View;
-class ViewTreeConnection;
+class Window;
+class WindowTreeConnection;
 
 // Interface implemented by an application using the view manager.
 //
-// Each call to OnEmbed() results in a new ViewTreeConnection and new root View.
-// ViewTreeConnection is deleted by any of the following:
+// Each call to OnEmbed() results in a new WindowTreeConnection and new root
+// View.
+// WindowTreeConnection is deleted by any of the following:
 // . If the root of the connection is destroyed. This happens if the owner
 //   of the root Embed()s another app in root, or the owner explicitly deletes
 //   root.
 // . The connection to the view manager is lost.
 // . Explicitly by way of calling delete.
 //
-// When the ViewTreeConnection is deleted all views are deleted (and observers
+// When the WindowTreeConnection is deleted all views are deleted (and observers
 // notified). This is followed by notifying the delegate by way of
 // OnConnectionLost().
-class ViewTreeDelegate {
+class WindowTreeDelegate {
  public:
   // Called when the application implementing this interface is embedded at
   // |root|.
@@ -43,21 +44,21 @@
   // the pipes connecting |services| and |exposed_services| to the embedder and
   // any services obtained from them are not broken and will continue to be
   // valid.
-  virtual void OnEmbed(View* root) = 0;
+  virtual void OnEmbed(Window* root) = 0;
 
   // Sent when another app is embedded in the same View as this connection.
   // Subsequently the root View and this object are destroyed (observers are
   // notified appropriately).
   virtual void OnUnembed();
 
-  // Called from the destructor of ViewTreeConnection after all the Views have
+  // Called from the destructor of WindowTreeConnection after all the Views have
   // been destroyed. |connection| is no longer valid after this call.
-  virtual void OnConnectionLost(ViewTreeConnection* connection) = 0;
+  virtual void OnConnectionLost(WindowTreeConnection* connection) = 0;
 
  protected:
-  virtual ~ViewTreeDelegate() {}
+  virtual ~WindowTreeDelegate() {}
 };
 
 }  // namespace mus
 
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_VIEW_TREE_DELEGATE_H_
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_DELEGATE_H_
diff --git a/components/mus/public/cpp/window_tree_host_factory.h b/components/mus/public/cpp/window_tree_host_factory.h
new file mode 100644
index 0000000..c4e0790
--- /dev/null
+++ b/components/mus/public/cpp/window_tree_host_factory.h
@@ -0,0 +1,37 @@
+// 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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_HOST_FACTORY_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_HOST_FACTORY_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "components/mus/public/interfaces/view_tree.mojom.h"
+#include "components/mus/public/interfaces/view_tree_host.mojom.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
+
+namespace mojo {
+class ApplicationImpl;
+}
+
+namespace mus {
+
+class WindowTreeDelegate;
+
+// Uses |factory| to create a new |host|, providing the supplied |host_client|
+// which may be null. |delegate| must not be null.
+void CreateWindowTreeHost(mojo::ViewTreeHostFactory* factory,
+                          mojo::ViewTreeHostClientPtr host_client,
+                          WindowTreeDelegate* delegate,
+                          mojo::ViewTreeHostPtr* host);
+
+// Creates a single host with no client by connecting to the view manager
+// application. Useful only for tests and trivial UIs.
+void CreateSingleWindowTreeHost(mojo::ApplicationImpl* app,
+                                WindowTreeDelegate* delegate,
+                                mojo::ViewTreeHostPtr* host);
+
+}  // namespace mus
+
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_HOST_FACTORY_H_
diff --git a/components/mus/public/interfaces/view_tree.mojom b/components/mus/public/interfaces/view_tree.mojom
index 47ed4c7..b9889c0 100644
--- a/components/mus/public/interfaces/view_tree.mojom
+++ b/components/mus/public/interfaces/view_tree.mojom
@@ -98,17 +98,17 @@
   // . |child| is an ancestor of |parent|.
   // . |child| is already a child of |parent|.
   //
-  // This may result in a connection getting OnViewDeleted(). See
+  // This may result in a connection getting OnWindowDeleted(). See
   // RemoveViewFromParent for details.
   AddView(uint32 parent, uint32 child) => (bool success);
 
   // Removes a view from its current parent. This fails if the view is not
   // valid or the view already has no parent.
   //
-  // Removing a view from a parent may result in OnViewDeleted() being sent to
+  // Removing a view from a parent may result in OnWindowDeleted() being sent to
   // other connections. For example, connection A has views 1 and 2, with 2 a
   // child of 1. Connection B has a root 1. If 2 is removed from 1 then B gets
-  // OnViewDeleted(). This is done as view 2 is effectively no longer visible to
+  // OnWindowDeleted(). This is done as view 2 is effectively no longer visible to
   // connection B.
   RemoveViewFromParent(uint32 view_id) => (bool success);
 
@@ -144,7 +144,7 @@
   // A view may only have one embedding in it at a time. Subsequent calls to
   // Embed() for the same view result in the currently embedded
   // ViewTreeClient being removed. The embedded app is told this by way of
-  // OnUnembed(), which is followed by OnViewDeleted() (as the connection no
+  // OnUnembed(), which is followed by OnWindowDeleted() (as the connection no
   // longer has access to the view).
   //
   // The embedder can detect when the embedded app disconnects by way of
@@ -173,7 +173,7 @@
 
 // Changes to views are not sent to the connection that originated the
 // change. For example, if connection 1 changes the bounds of a view by calling
-// SetBounds(), connection 1 does not receive OnViewBoundsChanged().
+// SetBounds(), connection 1 does not receive OnWindowBoundsChanged().
 interface ViewTreeClient {
   // Invoked when the client application has been embedded at |root|.
   // See Embed() on ViewTree for more details. |tree| will be a handle back to
@@ -196,13 +196,13 @@
   OnUnembed();
 
   // Invoked when a view's bounds have changed.
-  OnViewBoundsChanged(uint32 view,
+  OnWindowBoundsChanged(uint32 view,
                       mojo.Rect old_bounds,
                       mojo.Rect new_bounds);
 
   // Invoked when the viewport metrics for the view have changed.
   // Clients are expected to propagate this to the view tree.
-  OnViewViewportMetricsChanged(mojo.ViewportMetrics old_metrics,
+  OnWindowViewportMetricsChanged(mojo.ViewportMetrics old_metrics,
                                mojo.ViewportMetrics new_metrics);
 
   // Invoked when a change is done to the hierarchy. A value of 0 is used to
@@ -211,21 +211,21 @@
   // |views| contains any views that are that the client has not been told
   // about. This is not sent for hierarchy changes of views not known to this
   // client or not attached to the tree.
-  OnViewHierarchyChanged(uint32 view,
+  OnWindowHierarchyChanged(uint32 view,
                          uint32 new_parent,
                          uint32 old_parent,
                          array<ViewData> views);
 
   // Invoked when the order of views within a parent changes.
-  OnViewReordered(uint32 view_id,
+  OnWindowReordered(uint32 view_id,
                   uint32 relative_view_id,
                   OrderDirection direction);
 
   // Invoked when a view is deleted.
-  OnViewDeleted(uint32 view);
+  OnWindowDeleted(uint32 view);
 
   // Invoked when the visibility of the specified view changes.
-  OnViewVisibilityChanged(uint32 view, bool visible);
+  OnWindowVisibilityChanged(uint32 view, bool visible);
 
   // Invoked when a change to the visibility of |view| or one if it's ancestors
   // is done such that the drawn state changes. This is only invoked for the
@@ -236,15 +236,15 @@
   // the drawn state of B1 has changed (to false), but is not told anything
   // about B2 as it's drawn state can be calculated from that of B1.
   //
-  // NOTE: This is not invoked if OnViewVisibilityChanged() is invoked.
-  OnViewDrawnStateChanged(uint32 view, bool drawn);
+  // NOTE: This is not invoked if OnWindowVisibilityChanged() is invoked.
+  OnWindowDrawnStateChanged(uint32 view, bool drawn);
 
   // Invoked when a view property is changed. If this change is a removal,
   // |new_data| is null.
-  OnViewSharedPropertyChanged(uint32 view, string name, array<uint8>? new_data);
+  OnWindowSharedPropertyChanged(uint32 view, string name, array<uint8>? new_data);
 
   // Invoked when an event is targeted at the specified view.
-  OnViewInputEvent(uint32 view, mojo.Event event) => ();
+  OnWindowInputEvent(uint32 view, mojo.Event event) => ();
 
-  OnViewFocused(uint32 focused_view_id);
+  OnWindowFocused(uint32 focused_view_id);
 };
diff --git a/components/mus/public/interfaces/view_tree_host.mojom b/components/mus/public/interfaces/view_tree_host.mojom
index 74ef56b..2d436bde 100644
--- a/components/mus/public/interfaces/view_tree_host.mojom
+++ b/components/mus/public/interfaces/view_tree_host.mojom
@@ -35,7 +35,7 @@
 };
 
 interface ViewTreeHostFactory {
-  CreateViewTreeHost(ViewTreeHost& view_tree_host,
-                     ViewTreeHostClient? host_client,
-                     ViewTreeClient tree_client);
+  CreateWindowTreeHost(ViewTreeHost& view_tree_host,
+                       ViewTreeHostClient? host_client,
+                       ViewTreeClient tree_client);
 };
diff --git a/components/mus/public/interfaces/window_manager.mojom b/components/mus/public/interfaces/window_manager.mojom
index ea51794..0bedd1f 100644
--- a/components/mus/public/interfaces/window_manager.mojom
+++ b/components/mus/public/interfaces/window_manager.mojom
@@ -7,6 +7,21 @@
 import "components/mus/public/interfaces/view_tree.mojom";
 import "ui/mojo/geometry/geometry.mojom";
 
+enum Rotation {
+  VALUE_0,
+  VALUE_90,
+  VALUE_180,
+  VALUE_270,
+};
+
+struct Display {
+  int64 id;
+  mojo.Rect bounds;
+  mojo.Rect work_area;
+  float device_pixel_ratio;
+  Rotation rotation;
+};
+
 // Represents a core interface that should be implemented by any window manager
 // built on top of Mus.
 // For security reasons, methods that take view_ids can only pass view ids
@@ -18,4 +33,6 @@
   // Resizes the corresponding view to |size| and centers it in the current
   // context.
   CenterWindow(uint32 view_id, mojo.Size size);
+
+  GetDisplays() => (array<Display> displays);
 };
diff --git a/components/mus/vm/access_policy.h b/components/mus/vm/access_policy.h
index d28e678..f2862b4 100644
--- a/components/mus/vm/access_policy.h
+++ b/components/mus/vm/access_policy.h
@@ -35,7 +35,7 @@
   virtual bool CanEmbed(const ServerView* view,
                         uint32_t policy_bitmask) const = 0;
   virtual bool CanChangeViewVisibility(const ServerView* view) const = 0;
-  virtual bool CanSetViewSurfaceId(const ServerView* view) const = 0;
+  virtual bool CanSetWindowSurfaceId(const ServerView* view) const = 0;
   virtual bool CanSetViewBounds(const ServerView* view) const = 0;
   virtual bool CanSetViewProperties(const ServerView* view) const = 0;
   virtual bool CanSetViewTextInputState(const ServerView* view) const = 0;
diff --git a/components/mus/vm/default_access_policy.cc b/components/mus/vm/default_access_policy.cc
index 852f310..f2a049a 100644
--- a/components/mus/vm/default_access_policy.cc
+++ b/components/mus/vm/default_access_policy.cc
@@ -73,9 +73,10 @@
          delegate_->IsRootForAccessPolicy(view->id());
 }
 
-bool DefaultAccessPolicy::CanSetViewSurfaceId(const ServerView* view) const {
+bool DefaultAccessPolicy::CanSetWindowSurfaceId(const ServerView* view) const {
   // Once a view embeds another app, the embedder app is no longer able to
-  // call SetViewSurfaceId() - this ability is transferred to the embedded app.
+  // call SetWindowSurfaceId() - this ability is transferred to the embedded
+  // app.
   if (delegate_->IsViewRootOfAnotherConnectionForAccessPolicy(view))
     return false;
   return WasCreatedByThisConnection(view) ||
diff --git a/components/mus/vm/default_access_policy.h b/components/mus/vm/default_access_policy.h
index 194c903..6bda02e 100644
--- a/components/mus/vm/default_access_policy.h
+++ b/components/mus/vm/default_access_policy.h
@@ -31,7 +31,7 @@
   bool CanDescendIntoViewForViewTree(const ServerView* view) const override;
   bool CanEmbed(const ServerView* view, uint32_t policy_bitmask) const override;
   bool CanChangeViewVisibility(const ServerView* view) const override;
-  bool CanSetViewSurfaceId(const ServerView* view) const override;
+  bool CanSetWindowSurfaceId(const ServerView* view) const override;
   bool CanSetViewBounds(const ServerView* view) const override;
   bool CanSetViewProperties(const ServerView* view) const override;
   bool CanSetViewTextInputState(const ServerView* view) const override;
diff --git a/components/mus/vm/test_change_tracker.cc b/components/mus/vm/test_change_tracker.cc
index 3a3dd978..9ff3b114 100644
--- a/components/mus/vm/test_change_tracker.cc
+++ b/components/mus/vm/test_change_tracker.cc
@@ -187,9 +187,9 @@
   AddChange(change);
 }
 
-void TestChangeTracker::OnViewBoundsChanged(Id view_id,
-                                            mojo::RectPtr old_bounds,
-                                            mojo::RectPtr new_bounds) {
+void TestChangeTracker::OnWindowBoundsChanged(Id view_id,
+                                              mojo::RectPtr old_bounds,
+                                              mojo::RectPtr new_bounds) {
   Change change;
   change.type = CHANGE_TYPE_NODE_BOUNDS_CHANGED;
   change.view_id = view_id;
@@ -210,7 +210,7 @@
   AddChange(change);
 }
 
-void TestChangeTracker::OnViewViewportMetricsChanged(
+void TestChangeTracker::OnWindowViewportMetricsChanged(
     mojo::ViewportMetricsPtr old_metrics,
     mojo::ViewportMetricsPtr new_metrics) {
   Change change;
@@ -219,10 +219,10 @@
   AddChange(change);
 }
 
-void TestChangeTracker::OnViewHierarchyChanged(Id view_id,
-                                               Id new_parent_id,
-                                               Id old_parent_id,
-                                               Array<ViewDataPtr> views) {
+void TestChangeTracker::OnWindowHierarchyChanged(Id view_id,
+                                                 Id new_parent_id,
+                                                 Id old_parent_id,
+                                                 Array<ViewDataPtr> views) {
   Change change;
   change.type = CHANGE_TYPE_NODE_HIERARCHY_CHANGED;
   change.view_id = view_id;
@@ -232,9 +232,9 @@
   AddChange(change);
 }
 
-void TestChangeTracker::OnViewReordered(Id view_id,
-                                        Id relative_view_id,
-                                        mojo::OrderDirection direction) {
+void TestChangeTracker::OnWindowReordered(Id view_id,
+                                          Id relative_view_id,
+                                          mojo::OrderDirection direction) {
   Change change;
   change.type = CHANGE_TYPE_NODE_REORDERED;
   change.view_id = view_id;
@@ -243,14 +243,14 @@
   AddChange(change);
 }
 
-void TestChangeTracker::OnViewDeleted(Id view_id) {
+void TestChangeTracker::OnWindowDeleted(Id view_id) {
   Change change;
   change.type = CHANGE_TYPE_NODE_DELETED;
   change.view_id = view_id;
   AddChange(change);
 }
 
-void TestChangeTracker::OnViewVisibilityChanged(Id view_id, bool visible) {
+void TestChangeTracker::OnWindowVisibilityChanged(Id view_id, bool visible) {
   Change change;
   change.type = CHANGE_TYPE_NODE_VISIBILITY_CHANGED;
   change.view_id = view_id;
@@ -258,7 +258,7 @@
   AddChange(change);
 }
 
-void TestChangeTracker::OnViewDrawnStateChanged(Id view_id, bool drawn) {
+void TestChangeTracker::OnWindowDrawnStateChanged(Id view_id, bool drawn) {
   Change change;
   change.type = CHANGE_TYPE_NODE_DRAWN_STATE_CHANGED;
   change.view_id = view_id;
@@ -266,7 +266,7 @@
   AddChange(change);
 }
 
-void TestChangeTracker::OnViewInputEvent(Id view_id, mojo::EventPtr event) {
+void TestChangeTracker::OnWindowInputEvent(Id view_id, mojo::EventPtr event) {
   Change change;
   change.type = CHANGE_TYPE_INPUT_EVENT;
   change.view_id = view_id;
@@ -274,9 +274,9 @@
   AddChange(change);
 }
 
-void TestChangeTracker::OnViewSharedPropertyChanged(Id view_id,
-                                                    String name,
-                                                    Array<uint8_t> data) {
+void TestChangeTracker::OnWindowSharedPropertyChanged(Id view_id,
+                                                      String name,
+                                                      Array<uint8_t> data) {
   Change change;
   change.type = CHANGE_TYPE_PROPERTY_CHANGED;
   change.view_id = view_id;
@@ -288,7 +288,7 @@
   AddChange(change);
 }
 
-void TestChangeTracker::OnViewFocused(Id view_id) {
+void TestChangeTracker::OnWindowFocused(Id view_id) {
   Change change;
   change.type = CHANGE_TYPE_FOCUSED;
   change.view_id = view_id;
diff --git a/components/mus/vm/test_change_tracker.h b/components/mus/vm/test_change_tracker.h
index 1896de2..aa1514b6 100644
--- a/components/mus/vm/test_change_tracker.h
+++ b/components/mus/vm/test_change_tracker.h
@@ -120,26 +120,26 @@
   void OnEmbed(ConnectionSpecificId connection_id, mojo::ViewDataPtr root);
   void OnEmbeddedAppDisconnected(Id view_id);
   void OnUnembed();
-  void OnViewBoundsChanged(Id view_id,
-                           mojo::RectPtr old_bounds,
-                           mojo::RectPtr new_bounds);
-  void OnViewViewportMetricsChanged(mojo::ViewportMetricsPtr old_bounds,
-                                    mojo::ViewportMetricsPtr new_bounds);
-  void OnViewHierarchyChanged(Id view_id,
-                              Id new_parent_id,
-                              Id old_parent_id,
-                              mojo::Array<mojo::ViewDataPtr> views);
-  void OnViewReordered(Id view_id,
-                       Id relative_view_id,
-                       mojo::OrderDirection direction);
-  void OnViewDeleted(Id view_id);
-  void OnViewVisibilityChanged(Id view_id, bool visible);
-  void OnViewDrawnStateChanged(Id view_id, bool drawn);
-  void OnViewInputEvent(Id view_id, mojo::EventPtr event);
-  void OnViewSharedPropertyChanged(Id view_id,
-                                   mojo::String name,
-                                   mojo::Array<uint8_t> data);
-  void OnViewFocused(Id view_id);
+  void OnWindowBoundsChanged(Id view_id,
+                             mojo::RectPtr old_bounds,
+                             mojo::RectPtr new_bounds);
+  void OnWindowViewportMetricsChanged(mojo::ViewportMetricsPtr old_bounds,
+                                      mojo::ViewportMetricsPtr new_bounds);
+  void OnWindowHierarchyChanged(Id view_id,
+                                Id new_parent_id,
+                                Id old_parent_id,
+                                mojo::Array<mojo::ViewDataPtr> views);
+  void OnWindowReordered(Id view_id,
+                         Id relative_view_id,
+                         mojo::OrderDirection direction);
+  void OnWindowDeleted(Id view_id);
+  void OnWindowVisibilityChanged(Id view_id, bool visible);
+  void OnWindowDrawnStateChanged(Id view_id, bool drawn);
+  void OnWindowInputEvent(Id view_id, mojo::EventPtr event);
+  void OnWindowSharedPropertyChanged(Id view_id,
+                                     mojo::String name,
+                                     mojo::Array<uint8_t> data);
+  void OnWindowFocused(Id view_id);
   void DelegateEmbed(const mojo::String& url);
 
  private:
diff --git a/components/mus/vm/view_manager_client_apptest.cc b/components/mus/vm/view_manager_client_apptest.cc
index 1b38820..9d6e1af 100644
--- a/components/mus/vm/view_manager_client_apptest.cc
+++ b/components/mus/vm/view_manager_client_apptest.cc
@@ -5,11 +5,11 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/run_loop.h"
-#include "components/mus/public/cpp/tests/view_manager_test_base.h"
+#include "components/mus/public/cpp/tests/window_server_test_base.h"
 #include "components/mus/public/cpp/util.h"
-#include "components/mus/public/cpp/view_observer.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/application/public/cpp/application_test_base.h"
@@ -19,133 +19,142 @@
 
 namespace {
 
-class BoundsChangeObserver : public ViewObserver {
+class BoundsChangeObserver : public WindowObserver {
  public:
-  explicit BoundsChangeObserver(View* view) : view_(view) {
-    view_->AddObserver(this);
+  explicit BoundsChangeObserver(Window* window) : window_(window) {
+    window_->AddObserver(this);
   }
-  ~BoundsChangeObserver() override { view_->RemoveObserver(this); }
+  ~BoundsChangeObserver() override { window_->RemoveObserver(this); }
 
  private:
-  // Overridden from ViewObserver:
-  void OnViewBoundsChanged(View* view,
-                           const mojo::Rect& old_bounds,
-                           const mojo::Rect& new_bounds) override {
-    DCHECK_EQ(view, view_);
-    EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
+  // Overridden from WindowObserver:
+  void OnWindowBoundsChanged(Window* window,
+                             const mojo::Rect& old_bounds,
+                             const mojo::Rect& new_bounds) override {
+    DCHECK_EQ(window, window_);
+    EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
   }
 
-  View* view_;
+  Window* window_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver);
 };
 
-// Wait until the bounds of the supplied view change; returns false on timeout.
-bool WaitForBoundsToChange(View* view) {
-  BoundsChangeObserver observer(view);
-  return ViewManagerTestBase::DoRunLoopWithTimeout();
+// Wait until the bounds of the supplied window change; returns false on
+// timeout.
+bool WaitForBoundsToChange(Window* window) {
+  BoundsChangeObserver observer(window);
+  return WindowServerTestBase::DoRunLoopWithTimeout();
 }
 
-// Spins a run loop until the tree beginning at |root| has |tree_size| views
+// Spins a run loop until the tree beginning at |root| has |tree_size| windows
 // (including |root|).
-class TreeSizeMatchesObserver : public ViewObserver {
+class TreeSizeMatchesObserver : public WindowObserver {
  public:
-  TreeSizeMatchesObserver(View* tree, size_t tree_size)
+  TreeSizeMatchesObserver(Window* tree, size_t tree_size)
       : tree_(tree), tree_size_(tree_size) {
     tree_->AddObserver(this);
   }
   ~TreeSizeMatchesObserver() override { tree_->RemoveObserver(this); }
 
-  bool IsTreeCorrectSize() { return CountViews(tree_) == tree_size_; }
+  bool IsTreeCorrectSize() { return CountWindows(tree_) == tree_size_; }
 
  private:
-  // Overridden from ViewObserver:
+  // Overridden from WindowObserver:
   void OnTreeChanged(const TreeChangeParams& params) override {
     if (IsTreeCorrectSize())
-      EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
+      EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
   }
 
-  size_t CountViews(const View* view) const {
+  size_t CountWindows(const Window* window) const {
     size_t count = 1;
-    View::Children::const_iterator it = view->children().begin();
-    for (; it != view->children().end(); ++it)
-      count += CountViews(*it);
+    Window::Children::const_iterator it = window->children().begin();
+    for (; it != window->children().end(); ++it)
+      count += CountWindows(*it);
     return count;
   }
 
-  View* tree_;
+  Window* tree_;
   size_t tree_size_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver);
 };
 
-// Wait until |view| has |tree_size| descendants; returns false on timeout. The
-// count includes |view|. For example, if you want to wait for |view| to have
+// Wait until |window| has |tree_size| descendants; returns false on timeout.
+// The
+// count includes |window|. For example, if you want to wait for |window| to
+// have
 // a single child, use a |tree_size| of 2.
-bool WaitForTreeSizeToMatch(View* view, size_t tree_size) {
-  TreeSizeMatchesObserver observer(view, tree_size);
+bool WaitForTreeSizeToMatch(Window* window, size_t tree_size) {
+  TreeSizeMatchesObserver observer(window, tree_size);
   return observer.IsTreeCorrectSize() ||
-         ViewManagerTestBase::DoRunLoopWithTimeout();
+         WindowServerTestBase::DoRunLoopWithTimeout();
 }
 
-class OrderChangeObserver : public ViewObserver {
+class OrderChangeObserver : public WindowObserver {
  public:
-  OrderChangeObserver(View* view) : view_(view) { view_->AddObserver(this); }
-  ~OrderChangeObserver() override { view_->RemoveObserver(this); }
+  OrderChangeObserver(Window* window) : window_(window) {
+    window_->AddObserver(this);
+  }
+  ~OrderChangeObserver() override { window_->RemoveObserver(this); }
 
  private:
-  // Overridden from ViewObserver:
-  void OnViewReordered(View* view,
-                       View* relative_view,
-                       mojo::OrderDirection direction) override {
-    DCHECK_EQ(view, view_);
-    EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
+  // Overridden from WindowObserver:
+  void OnWindowReordered(Window* window,
+                         Window* relative_window,
+                         mojo::OrderDirection direction) override {
+    DCHECK_EQ(window, window_);
+    EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
   }
 
-  View* view_;
+  Window* window_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver);
 };
 
-// Wait until |view|'s tree size matches |tree_size|; returns false on timeout.
-bool WaitForOrderChange(ViewTreeConnection* connection, View* view) {
-  OrderChangeObserver observer(view);
-  return ViewManagerTestBase::DoRunLoopWithTimeout();
+// Wait until |window|'s tree size matches |tree_size|; returns false on
+// timeout.
+bool WaitForOrderChange(WindowTreeConnection* connection, Window* window) {
+  OrderChangeObserver observer(window);
+  return WindowServerTestBase::DoRunLoopWithTimeout();
 }
 
-// Tracks a view's destruction. Query is_valid() for current state.
-class ViewTracker : public ViewObserver {
+// Tracks a window's destruction. Query is_valid() for current state.
+class WindowTracker : public WindowObserver {
  public:
-  explicit ViewTracker(View* view) : view_(view) { view_->AddObserver(this); }
-  ~ViewTracker() override {
-    if (view_)
-      view_->RemoveObserver(this);
+  explicit WindowTracker(Window* window) : window_(window) {
+    window_->AddObserver(this);
+  }
+  ~WindowTracker() override {
+    if (window_)
+      window_->RemoveObserver(this);
   }
 
-  bool is_valid() const { return !!view_; }
+  bool is_valid() const { return !!window_; }
 
  private:
-  // Overridden from ViewObserver:
-  void OnViewDestroyed(View* view) override {
-    DCHECK_EQ(view, view_);
-    view_ = nullptr;
+  // Overridden from WindowObserver:
+  void OnWindowDestroyed(Window* window) override {
+    DCHECK_EQ(window, window_);
+    window_ = nullptr;
   }
 
-  View* view_;
+  Window* window_;
 
-  MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTracker);
+  MOJO_DISALLOW_COPY_AND_ASSIGN(WindowTracker);
 };
 
 }  // namespace
 
-// ViewManager -----------------------------------------------------------------
+// WindowServer
+// -----------------------------------------------------------------
 
 struct EmbedResult {
-  EmbedResult(ViewTreeConnection* connection, ConnectionSpecificId id)
+  EmbedResult(WindowTreeConnection* connection, ConnectionSpecificId id)
       : connection(connection), connection_id(id) {}
   EmbedResult() : connection(nullptr), connection_id(0) {}
 
-  ViewTreeConnection* connection;
+  WindowTreeConnection* connection;
 
   // The id supplied to the callback from OnEmbed(). Depending upon the
   // access policy this may or may not match the connection id of
@@ -153,29 +162,30 @@
   ConnectionSpecificId connection_id;
 };
 
-// These tests model synchronization of two peer connections to the view manager
-// service, that are given access to some root view.
+// These tests model synchronization of two peer connections to the window
+// manager
+// service, that are given access to some root window.
 
-class ViewManagerTest : public ViewManagerTestBase {
+class WindowServerTest : public WindowServerTestBase {
  public:
-  ViewManagerTest() {}
+  WindowServerTest() {}
 
-  // Embeds another version of the test app @ view. This runs a run loop until
-  // a response is received, or a timeout. On success the new ViewManager is
+  // Embeds another version of the test app @ window. This runs a run loop until
+  // a response is received, or a timeout. On success the new WindowServer is
   // returned.
-  EmbedResult Embed(View* view) {
-    return Embed(view, mojo::ViewTree::ACCESS_POLICY_DEFAULT);
+  EmbedResult Embed(Window* window) {
+    return Embed(window, mojo::ViewTree::ACCESS_POLICY_DEFAULT);
   }
 
-  EmbedResult Embed(View* view, uint32_t access_policy_bitmask) {
+  EmbedResult Embed(Window* window, uint32_t access_policy_bitmask) {
     DCHECK(!embed_details_);
     embed_details_.reset(new EmbedDetails);
-    view->Embed(ConnectToApplicationAndGetViewManagerClient(),
-                access_policy_bitmask,
-                base::Bind(&ViewManagerTest::EmbedCallbackImpl,
-                           base::Unretained(this)));
+    window->Embed(ConnectToApplicationAndGetWindowServerClient(),
+                  access_policy_bitmask,
+                  base::Bind(&WindowServerTest::EmbedCallbackImpl,
+                             base::Unretained(this)));
     embed_details_->waiting = true;
-    if (!ViewManagerTestBase::DoRunLoopWithTimeout())
+    if (!WindowServerTestBase::DoRunLoopWithTimeout())
       return EmbedResult();
     const EmbedResult result(embed_details_->connection,
                              embed_details_->connection_id);
@@ -185,7 +195,7 @@
 
   // Establishes a connection to this application and asks for a
   // ViewTreeClient.
-  mojo::ViewTreeClientPtr ConnectToApplicationAndGetViewManagerClient() {
+  mojo::ViewTreeClientPtr ConnectToApplicationAndGetWindowServerClient() {
     mojo::URLRequestPtr request(mojo::URLRequest::New());
     request->url = mojo::String::From(application_impl()->url());
     scoped_ptr<mojo::ApplicationConnection> connection =
@@ -195,20 +205,20 @@
     return client.Pass();
   }
 
-  // ViewManagerTestBase:
-  void OnEmbed(View* root) override {
+  // WindowServerTestBase:
+  void OnEmbed(Window* root) override {
     if (!embed_details_) {
-      ViewManagerTestBase::OnEmbed(root);
+      WindowServerTestBase::OnEmbed(root);
       return;
     }
 
     embed_details_->connection = root->connection();
     if (embed_details_->callback_run)
-      EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
+      EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
   }
 
  private:
-  // Used to track the state of a call to view->Embed().
+  // Used to track the state of a call to window->Embed().
   struct EmbedDetails {
     EmbedDetails()
         : callback_run(false),
@@ -229,9 +239,9 @@
     // Connection id supplied to the Embed() callback.
     ConnectionSpecificId connection_id;
 
-    // The ViewTreeConnection that resulted from the Embed(). null if |result|
+    // The WindowTreeConnection that resulted from the Embed(). null if |result|
     // is false.
-    ViewTreeConnection* connection;
+    WindowTreeConnection* connection;
   };
 
   void EmbedCallbackImpl(bool result, ConnectionSpecificId connection_id) {
@@ -239,217 +249,218 @@
     embed_details_->result = result;
     embed_details_->connection_id = connection_id;
     if (embed_details_->waiting && (!result || embed_details_->connection))
-      EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
+      EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
   }
 
   scoped_ptr<EmbedDetails> embed_details_;
 
-  MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerTest);
+  MOJO_DISALLOW_COPY_AND_ASSIGN(WindowServerTest);
 };
 
-TEST_F(ViewManagerTest, RootView) {
+TEST_F(WindowServerTest, RootWindow) {
   ASSERT_NE(nullptr, window_manager());
   EXPECT_NE(nullptr, window_manager()->GetRoot());
 }
 
-TEST_F(ViewManagerTest, Embed) {
-  View* view = window_manager()->CreateView();
-  ASSERT_NE(nullptr, view);
-  view->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view);
-  ViewTreeConnection* embedded = Embed(view).connection;
+TEST_F(WindowServerTest, Embed) {
+  Window* window = window_manager()->CreateWindow();
+  ASSERT_NE(nullptr, window);
+  window->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window);
+  WindowTreeConnection* embedded = Embed(window).connection;
   ASSERT_NE(nullptr, embedded);
 
-  View* view_in_embedded = embedded->GetRoot();
-  ASSERT_NE(nullptr, view_in_embedded);
-  EXPECT_EQ(view->id(), view_in_embedded->id());
-  EXPECT_EQ(nullptr, view_in_embedded->parent());
-  EXPECT_TRUE(view_in_embedded->children().empty());
+  Window* window_in_embedded = embedded->GetRoot();
+  ASSERT_NE(nullptr, window_in_embedded);
+  EXPECT_EQ(window->id(), window_in_embedded->id());
+  EXPECT_EQ(nullptr, window_in_embedded->parent());
+  EXPECT_TRUE(window_in_embedded->children().empty());
 }
 
-// Window manager has two views, N1 and N11. Embeds A at N1. A should not see
+// Window manager has two windows, N1 and N11. Embeds A at N1. A should not see
 // N11.
-TEST_F(ViewManagerTest, EmbeddedDoesntSeeChild) {
-  View* view = window_manager()->CreateView();
-  ASSERT_NE(nullptr, view);
-  view->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view);
-  View* nested = window_manager()->CreateView();
+TEST_F(WindowServerTest, EmbeddedDoesntSeeChild) {
+  Window* window = window_manager()->CreateWindow();
+  ASSERT_NE(nullptr, window);
+  window->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window);
+  Window* nested = window_manager()->CreateWindow();
   ASSERT_NE(nullptr, nested);
   nested->SetVisible(true);
-  view->AddChild(nested);
+  window->AddChild(nested);
 
-  ViewTreeConnection* embedded = Embed(view).connection;
+  WindowTreeConnection* embedded = Embed(window).connection;
   ASSERT_NE(nullptr, embedded);
-  View* view_in_embedded = embedded->GetRoot();
-  EXPECT_EQ(view->id(), view_in_embedded->id());
-  EXPECT_EQ(nullptr, view_in_embedded->parent());
-  EXPECT_TRUE(view_in_embedded->children().empty());
+  Window* window_in_embedded = embedded->GetRoot();
+  EXPECT_EQ(window->id(), window_in_embedded->id());
+  EXPECT_EQ(nullptr, window_in_embedded->parent());
+  EXPECT_TRUE(window_in_embedded->children().empty());
 }
 
 // TODO(beng): write a replacement test for the one that once existed here:
 // This test validates the following scenario:
-// -  a view originating from one connection
-// -  a view originating from a second connection
-// +  the connection originating the view is destroyed
-// -> the view should still exist (since the second connection is live) but
-//    should be disconnected from any views.
+// -  a window originating from one connection
+// -  a window originating from a second connection
+// +  the connection originating the window is destroyed
+// -> the window should still exist (since the second connection is live) but
+//    should be disconnected from any windows.
 // http://crbug.com/396300
 //
 // TODO(beng): The new test should validate the scenario as described above
 //             except that the second connection still has a valid tree.
 
-// Verifies that bounds changes applied to a view hierarchy in one connection
+// Verifies that bounds changes applied to a window hierarchy in one connection
 // are reflected to another.
-TEST_F(ViewManagerTest, SetBounds) {
-  View* view = window_manager()->CreateView();
-  view->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view);
-  ViewTreeConnection* embedded = Embed(view).connection;
+TEST_F(WindowServerTest, SetBounds) {
+  Window* window = window_manager()->CreateWindow();
+  window->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window);
+  WindowTreeConnection* embedded = Embed(window).connection;
   ASSERT_NE(nullptr, embedded);
 
-  View* view_in_embedded = embedded->GetViewById(view->id());
-  EXPECT_EQ(view->bounds(), view_in_embedded->bounds());
+  Window* window_in_embedded = embedded->GetWindowById(window->id());
+  EXPECT_EQ(window->bounds(), window_in_embedded->bounds());
 
   mojo::Rect rect;
   rect.width = rect.height = 100;
-  view->SetBounds(rect);
-  ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded));
-  EXPECT_EQ(view->bounds(), view_in_embedded->bounds());
+  window->SetBounds(rect);
+  ASSERT_TRUE(WaitForBoundsToChange(window_in_embedded));
+  EXPECT_EQ(window->bounds(), window_in_embedded->bounds());
 }
 
-// Verifies that bounds changes applied to a view owned by a different
+// Verifies that bounds changes applied to a window owned by a different
 // connection are refused.
-TEST_F(ViewManagerTest, SetBoundsSecurity) {
-  View* view = window_manager()->CreateView();
-  view->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view);
-  ViewTreeConnection* embedded = Embed(view).connection;
+TEST_F(WindowServerTest, SetBoundsSecurity) {
+  Window* window = window_manager()->CreateWindow();
+  window->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window);
+  WindowTreeConnection* embedded = Embed(window).connection;
   ASSERT_NE(nullptr, embedded);
 
-  View* view_in_embedded = embedded->GetViewById(view->id());
+  Window* window_in_embedded = embedded->GetWindowById(window->id());
   mojo::Rect rect;
   rect.width = 800;
   rect.height = 600;
-  view->SetBounds(rect);
-  ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded));
+  window->SetBounds(rect);
+  ASSERT_TRUE(WaitForBoundsToChange(window_in_embedded));
 
   rect.width = 1024;
   rect.height = 768;
-  view_in_embedded->SetBounds(rect);
+  window_in_embedded->SetBounds(rect);
   // Bounds change should have been rejected.
-  EXPECT_EQ(view->bounds(), view_in_embedded->bounds());
+  EXPECT_EQ(window->bounds(), window_in_embedded->bounds());
 }
 
-// Verifies that a view can only be destroyed by the connection that created it.
-TEST_F(ViewManagerTest, DestroySecurity) {
-  View* view = window_manager()->CreateView();
-  view->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view);
-  ViewTreeConnection* embedded = Embed(view).connection;
+// Verifies that a window can only be destroyed by the connection that created
+// it.
+TEST_F(WindowServerTest, DestroySecurity) {
+  Window* window = window_manager()->CreateWindow();
+  window->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window);
+  WindowTreeConnection* embedded = Embed(window).connection;
   ASSERT_NE(nullptr, embedded);
 
-  View* view_in_embedded = embedded->GetViewById(view->id());
+  Window* window_in_embedded = embedded->GetWindowById(window->id());
 
-  ViewTracker tracker2(view_in_embedded);
-  view_in_embedded->Destroy();
-  // View should not have been destroyed.
+  WindowTracker tracker2(window_in_embedded);
+  window_in_embedded->Destroy();
+  // Window should not have been destroyed.
   EXPECT_TRUE(tracker2.is_valid());
 
-  ViewTracker tracker1(view);
-  view->Destroy();
+  WindowTracker tracker1(window);
+  window->Destroy();
   EXPECT_FALSE(tracker1.is_valid());
 }
 
-TEST_F(ViewManagerTest, MultiRoots) {
-  View* view1 = window_manager()->CreateView();
-  view1->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view1);
-  View* view2 = window_manager()->CreateView();
-  view2->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view2);
-  ViewTreeConnection* embedded1 = Embed(view1).connection;
+TEST_F(WindowServerTest, MultiRoots) {
+  Window* window1 = window_manager()->CreateWindow();
+  window1->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window1);
+  Window* window2 = window_manager()->CreateWindow();
+  window2->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window2);
+  WindowTreeConnection* embedded1 = Embed(window1).connection;
   ASSERT_NE(nullptr, embedded1);
-  ViewTreeConnection* embedded2 = Embed(view2).connection;
+  WindowTreeConnection* embedded2 = Embed(window2).connection;
   ASSERT_NE(nullptr, embedded2);
   EXPECT_NE(embedded1, embedded2);
 }
 
 // TODO(alhaad): Currently, the RunLoop gets stuck waiting for order change.
 // Debug and re-enable this.
-TEST_F(ViewManagerTest, DISABLED_Reorder) {
-  View* view1 = window_manager()->CreateView();
-  view1->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view1);
+TEST_F(WindowServerTest, DISABLED_Reorder) {
+  Window* window1 = window_manager()->CreateWindow();
+  window1->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window1);
 
-  ViewTreeConnection* embedded = Embed(view1).connection;
+  WindowTreeConnection* embedded = Embed(window1).connection;
   ASSERT_NE(nullptr, embedded);
 
-  View* view11 = embedded->CreateView();
-  view11->SetVisible(true);
-  embedded->GetRoot()->AddChild(view11);
-  View* view12 = embedded->CreateView();
-  view12->SetVisible(true);
-  embedded->GetRoot()->AddChild(view12);
+  Window* window11 = embedded->CreateWindow();
+  window11->SetVisible(true);
+  embedded->GetRoot()->AddChild(window11);
+  Window* window12 = embedded->CreateWindow();
+  window12->SetVisible(true);
+  embedded->GetRoot()->AddChild(window12);
 
-  View* root_in_embedded = embedded->GetRoot();
+  Window* root_in_embedded = embedded->GetRoot();
 
   {
     ASSERT_TRUE(WaitForTreeSizeToMatch(root_in_embedded, 3u));
-    view11->MoveToFront();
+    window11->MoveToFront();
     ASSERT_TRUE(WaitForOrderChange(embedded, root_in_embedded));
 
     EXPECT_EQ(root_in_embedded->children().front(),
-              embedded->GetViewById(view12->id()));
+              embedded->GetWindowById(window12->id()));
     EXPECT_EQ(root_in_embedded->children().back(),
-              embedded->GetViewById(view11->id()));
+              embedded->GetWindowById(window11->id()));
   }
 
   {
-    view11->MoveToBack();
+    window11->MoveToBack();
     ASSERT_TRUE(
-        WaitForOrderChange(embedded, embedded->GetViewById(view11->id())));
+        WaitForOrderChange(embedded, embedded->GetWindowById(window11->id())));
 
     EXPECT_EQ(root_in_embedded->children().front(),
-              embedded->GetViewById(view11->id()));
+              embedded->GetWindowById(window11->id()));
     EXPECT_EQ(root_in_embedded->children().back(),
-              embedded->GetViewById(view12->id()));
+              embedded->GetWindowById(window12->id()));
   }
 }
 
 namespace {
 
-class VisibilityChangeObserver : public ViewObserver {
+class VisibilityChangeObserver : public WindowObserver {
  public:
-  explicit VisibilityChangeObserver(View* view) : view_(view) {
-    view_->AddObserver(this);
+  explicit VisibilityChangeObserver(Window* window) : window_(window) {
+    window_->AddObserver(this);
   }
-  ~VisibilityChangeObserver() override { view_->RemoveObserver(this); }
+  ~VisibilityChangeObserver() override { window_->RemoveObserver(this); }
 
  private:
-  // Overridden from ViewObserver:
-  void OnViewVisibilityChanged(View* view) override {
-    EXPECT_EQ(view, view_);
-    EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
+  // Overridden from WindowObserver:
+  void OnWindowVisibilityChanged(Window* window) override {
+    EXPECT_EQ(window, window_);
+    EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
   }
 
-  View* view_;
+  Window* window_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver);
 };
 
 }  // namespace
 
-TEST_F(ViewManagerTest, Visible) {
-  View* view1 = window_manager()->CreateView();
-  view1->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view1);
+TEST_F(WindowServerTest, Visible) {
+  Window* window1 = window_manager()->CreateWindow();
+  window1->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window1);
 
   // Embed another app and verify initial state.
-  ViewTreeConnection* embedded = Embed(view1).connection;
+  WindowTreeConnection* embedded = Embed(window1).connection;
   ASSERT_NE(nullptr, embedded);
   ASSERT_NE(nullptr, embedded->GetRoot());
-  View* embedded_root = embedded->GetRoot();
+  Window* embedded_root = embedded->GetRoot();
   EXPECT_TRUE(embedded_root->visible());
   EXPECT_TRUE(embedded_root->IsDrawn());
 
@@ -457,12 +468,12 @@
   // correctly to the embedded app.
   {
     VisibilityChangeObserver observer(embedded_root);
-    view1->SetVisible(false);
-    ASSERT_TRUE(ViewManagerTestBase::DoRunLoopWithTimeout());
+    window1->SetVisible(false);
+    ASSERT_TRUE(WindowServerTestBase::DoRunLoopWithTimeout());
   }
 
-  EXPECT_FALSE(view1->visible());
-  EXPECT_FALSE(view1->IsDrawn());
+  EXPECT_FALSE(window1->visible());
+  EXPECT_FALSE(window1->IsDrawn());
 
   EXPECT_FALSE(embedded_root->visible());
   EXPECT_FALSE(embedded_root->IsDrawn());
@@ -470,12 +481,12 @@
   // Make the node visible again.
   {
     VisibilityChangeObserver observer(embedded_root);
-    view1->SetVisible(true);
-    ASSERT_TRUE(ViewManagerTestBase::DoRunLoopWithTimeout());
+    window1->SetVisible(true);
+    ASSERT_TRUE(WindowServerTestBase::DoRunLoopWithTimeout());
   }
 
-  EXPECT_TRUE(view1->visible());
-  EXPECT_TRUE(view1->IsDrawn());
+  EXPECT_TRUE(window1->visible());
+  EXPECT_TRUE(window1->IsDrawn());
 
   EXPECT_TRUE(embedded_root->visible());
   EXPECT_TRUE(embedded_root->IsDrawn());
@@ -483,37 +494,37 @@
 
 namespace {
 
-class DrawnChangeObserver : public ViewObserver {
+class DrawnChangeObserver : public WindowObserver {
  public:
-  explicit DrawnChangeObserver(View* view) : view_(view) {
-    view_->AddObserver(this);
+  explicit DrawnChangeObserver(Window* window) : window_(window) {
+    window_->AddObserver(this);
   }
-  ~DrawnChangeObserver() override { view_->RemoveObserver(this); }
+  ~DrawnChangeObserver() override { window_->RemoveObserver(this); }
 
  private:
-  // Overridden from ViewObserver:
-  void OnViewDrawnChanged(View* view) override {
-    EXPECT_EQ(view, view_);
-    EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
+  // Overridden from WindowObserver:
+  void OnWindowDrawnChanged(Window* window) override {
+    EXPECT_EQ(window, window_);
+    EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
   }
 
-  View* view_;
+  Window* window_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver);
 };
 
 }  // namespace
 
-TEST_F(ViewManagerTest, Drawn) {
-  View* view1 = window_manager()->CreateView();
-  view1->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view1);
+TEST_F(WindowServerTest, Drawn) {
+  Window* window1 = window_manager()->CreateWindow();
+  window1->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window1);
 
   // Embed another app and verify initial state.
-  ViewTreeConnection* embedded = Embed(view1).connection;
+  WindowTreeConnection* embedded = Embed(window1).connection;
   ASSERT_NE(nullptr, embedded);
   ASSERT_NE(nullptr, embedded->GetRoot());
-  View* embedded_root = embedded->GetRoot();
+  Window* embedded_root = embedded->GetRoot();
   EXPECT_TRUE(embedded_root->visible());
   EXPECT_TRUE(embedded_root->IsDrawn());
 
@@ -525,64 +536,66 @@
     ASSERT_TRUE(DoRunLoopWithTimeout());
   }
 
-  EXPECT_TRUE(view1->visible());
-  EXPECT_FALSE(view1->IsDrawn());
+  EXPECT_TRUE(window1->visible());
+  EXPECT_FALSE(window1->IsDrawn());
 
   EXPECT_TRUE(embedded_root->visible());
   EXPECT_FALSE(embedded_root->IsDrawn());
 }
 
-// TODO(beng): tests for view event dispatcher.
-// - verify that we see events for all views.
+// TODO(beng): tests for window event dispatcher.
+// - verify that we see events for all windows.
 
 namespace {
 
-class FocusChangeObserver : public ViewObserver {
+class FocusChangeObserver : public WindowObserver {
  public:
-  explicit FocusChangeObserver(View* view)
-      : view_(view), last_gained_focus_(nullptr), last_lost_focus_(nullptr) {
-    view_->AddObserver(this);
+  explicit FocusChangeObserver(Window* window)
+      : window_(window),
+        last_gained_focus_(nullptr),
+        last_lost_focus_(nullptr) {
+    window_->AddObserver(this);
   }
-  ~FocusChangeObserver() override { view_->RemoveObserver(this); }
+  ~FocusChangeObserver() override { window_->RemoveObserver(this); }
 
-  View* last_gained_focus() { return last_gained_focus_; }
+  Window* last_gained_focus() { return last_gained_focus_; }
 
-  View* last_lost_focus() { return last_lost_focus_; }
+  Window* last_lost_focus() { return last_lost_focus_; }
 
  private:
-  // Overridden from ViewObserver.
-  void OnViewFocusChanged(View* gained_focus, View* lost_focus) override {
+  // Overridden from WindowObserver.
+  void OnWindowFocusChanged(Window* gained_focus, Window* lost_focus) override {
     EXPECT_TRUE(!gained_focus || gained_focus->HasFocus());
     EXPECT_FALSE(lost_focus && lost_focus->HasFocus());
     last_gained_focus_ = gained_focus;
     last_lost_focus_ = lost_focus;
-    EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
+    EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
   }
 
-  View* view_;
-  View* last_gained_focus_;
-  View* last_lost_focus_;
+  Window* window_;
+  Window* last_gained_focus_;
+  Window* last_lost_focus_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(FocusChangeObserver);
 };
 
 }  // namespace
 
-TEST_F(ViewManagerTest, Focus) {
-  View* view1 = window_manager()->CreateView();
-  view1->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view1);
+TEST_F(WindowServerTest, Focus) {
+  Window* window1 = window_manager()->CreateWindow();
+  window1->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window1);
 
-  ViewTreeConnection* embedded = Embed(view1).connection;
+  WindowTreeConnection* embedded = Embed(window1).connection;
   ASSERT_NE(nullptr, embedded);
-  View* view11 = embedded->CreateView();
-  view11->SetVisible(true);
-  embedded->GetRoot()->AddChild(view11);
+  Window* window11 = embedded->CreateWindow();
+  window11->SetVisible(true);
+  embedded->GetRoot()->AddChild(window11);
 
-  // TODO(alhaad): Figure out why switching focus between views from different
+  // TODO(alhaad): Figure out why switching focus between windows from different
   // connections is causing the tests to crash and add tests for that.
   {
-    View* embedded_root = embedded->GetRoot();
+    Window* embedded_root = embedded->GetRoot();
     FocusChangeObserver observer(embedded_root);
     embedded_root->SetFocus();
     ASSERT_TRUE(DoRunLoopWithTimeout());
@@ -590,56 +603,57 @@
     EXPECT_EQ(embedded_root->id(), observer.last_gained_focus()->id());
   }
   {
-    FocusChangeObserver observer(view11);
-    view11->SetFocus();
+    FocusChangeObserver observer(window11);
+    window11->SetFocus();
     ASSERT_TRUE(DoRunLoopWithTimeout());
     ASSERT_NE(nullptr, observer.last_gained_focus());
     ASSERT_NE(nullptr, observer.last_lost_focus());
-    EXPECT_EQ(view11->id(), observer.last_gained_focus()->id());
+    EXPECT_EQ(window11->id(), observer.last_gained_focus()->id());
     EXPECT_EQ(embedded->GetRoot()->id(), observer.last_lost_focus()->id());
   }
   {
-    // Add an observer on the View that loses focus, and make sure the observer
+    // Add an observer on the Window that loses focus, and make sure the
+    // observer
     // sees the right values.
-    FocusChangeObserver observer(view11);
+    FocusChangeObserver observer(window11);
     embedded->GetRoot()->SetFocus();
     ASSERT_TRUE(DoRunLoopWithTimeout());
     ASSERT_NE(nullptr, observer.last_gained_focus());
     ASSERT_NE(nullptr, observer.last_lost_focus());
-    EXPECT_EQ(view11->id(), observer.last_lost_focus()->id());
+    EXPECT_EQ(window11->id(), observer.last_lost_focus()->id());
     EXPECT_EQ(embedded->GetRoot()->id(), observer.last_gained_focus()->id());
   }
 }
 
 namespace {
 
-class DestroyedChangedObserver : public ViewObserver {
+class DestroyedChangedObserver : public WindowObserver {
  public:
-  DestroyedChangedObserver(ViewManagerTestBase* test,
-                           View* view,
+  DestroyedChangedObserver(WindowServerTestBase* test,
+                           Window* window,
                            bool* got_destroy)
-      : test_(test), view_(view), got_destroy_(got_destroy) {
-    view_->AddObserver(this);
+      : test_(test), window_(window), got_destroy_(got_destroy) {
+    window_->AddObserver(this);
   }
   ~DestroyedChangedObserver() override {
-    if (view_)
-      view_->RemoveObserver(this);
+    if (window_)
+      window_->RemoveObserver(this);
   }
 
  private:
-  // Overridden from ViewObserver:
-  void OnViewDestroyed(View* view) override {
-    EXPECT_EQ(view, view_);
-    view_->RemoveObserver(this);
+  // Overridden from WindowObserver:
+  void OnWindowDestroyed(Window* window) override {
+    EXPECT_EQ(window, window_);
+    window_->RemoveObserver(this);
     *got_destroy_ = true;
-    view_ = nullptr;
+    window_ = nullptr;
 
-    // We should always get OnViewDestroyed() before OnConnectionLost().
-    EXPECT_FALSE(test_->view_tree_connection_destroyed());
+    // We should always get OnWindowDestroyed() before OnConnectionLost().
+    EXPECT_FALSE(test_->window_tree_connection_destroyed());
   }
 
-  ViewManagerTestBase* test_;
-  View* view_;
+  WindowServerTestBase* test_;
+  Window* window_;
   bool* got_destroy_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyedChangedObserver);
@@ -647,73 +661,73 @@
 
 }  // namespace
 
-// Verifies deleting a ViewManager sends the right notifications.
-TEST_F(ViewManagerTest, DeleteViewManager) {
-  View* view = window_manager()->CreateView();
-  ASSERT_NE(nullptr, view);
-  view->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view);
-  ViewTreeConnection* connection = Embed(view).connection;
+// Verifies deleting a WindowServer sends the right notifications.
+TEST_F(WindowServerTest, DeleteWindowServer) {
+  Window* window = window_manager()->CreateWindow();
+  ASSERT_NE(nullptr, window);
+  window->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window);
+  WindowTreeConnection* connection = Embed(window).connection;
   ASSERT_TRUE(connection);
   bool got_destroy = false;
   DestroyedChangedObserver observer(this, connection->GetRoot(), &got_destroy);
   delete connection;
-  EXPECT_TRUE(view_tree_connection_destroyed());
+  EXPECT_TRUE(window_tree_connection_destroyed());
   EXPECT_TRUE(got_destroy);
 }
 
-// Verifies two Embed()s in the same view trigger deletion of the first
-// ViewManager.
-TEST_F(ViewManagerTest, DisconnectTriggersDelete) {
-  View* view = window_manager()->CreateView();
-  ASSERT_NE(nullptr, view);
-  view->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view);
-  ViewTreeConnection* connection = Embed(view).connection;
+// Verifies two Embed()s in the same window trigger deletion of the first
+// WindowServer.
+TEST_F(WindowServerTest, DisconnectTriggersDelete) {
+  Window* window = window_manager()->CreateWindow();
+  ASSERT_NE(nullptr, window);
+  window->SetVisible(true);
+  window_manager()->GetRoot()->AddChild(window);
+  WindowTreeConnection* connection = Embed(window).connection;
   EXPECT_NE(connection, window_manager());
-  View* embedded_view = connection->CreateView();
+  Window* embedded_window = connection->CreateWindow();
   // Embed again, this should trigger disconnect and deletion of connection.
   bool got_destroy;
-  DestroyedChangedObserver observer(this, embedded_view, &got_destroy);
-  EXPECT_FALSE(view_tree_connection_destroyed());
-  Embed(view);
-  EXPECT_TRUE(view_tree_connection_destroyed());
+  DestroyedChangedObserver observer(this, embedded_window, &got_destroy);
+  EXPECT_FALSE(window_tree_connection_destroyed());
+  Embed(window);
+  EXPECT_TRUE(window_tree_connection_destroyed());
 }
 
-class ViewRemovedFromParentObserver : public ViewObserver {
+class WindowRemovedFromParentObserver : public WindowObserver {
  public:
-  explicit ViewRemovedFromParentObserver(View* view)
-      : view_(view), was_removed_(false) {
-    view_->AddObserver(this);
+  explicit WindowRemovedFromParentObserver(Window* window)
+      : window_(window), was_removed_(false) {
+    window_->AddObserver(this);
   }
-  ~ViewRemovedFromParentObserver() override { view_->RemoveObserver(this); }
+  ~WindowRemovedFromParentObserver() override { window_->RemoveObserver(this); }
 
   bool was_removed() const { return was_removed_; }
 
  private:
-  // Overridden from ViewObserver:
+  // Overridden from WindowObserver:
   void OnTreeChanged(const TreeChangeParams& params) override {
-    if (params.target == view_ && !params.new_parent)
+    if (params.target == window_ && !params.new_parent)
       was_removed_ = true;
   }
 
-  View* view_;
+  Window* window_;
   bool was_removed_;
 
-  MOJO_DISALLOW_COPY_AND_ASSIGN(ViewRemovedFromParentObserver);
+  MOJO_DISALLOW_COPY_AND_ASSIGN(WindowRemovedFromParentObserver);
 };
 
-TEST_F(ViewManagerTest, EmbedRemovesChildren) {
-  View* view1 = window_manager()->CreateView();
-  View* view2 = window_manager()->CreateView();
-  window_manager()->GetRoot()->AddChild(view1);
-  view1->AddChild(view2);
+TEST_F(WindowServerTest, EmbedRemovesChildren) {
+  Window* window1 = window_manager()->CreateWindow();
+  Window* window2 = window_manager()->CreateWindow();
+  window_manager()->GetRoot()->AddChild(window1);
+  window1->AddChild(window2);
 
-  ViewRemovedFromParentObserver observer(view2);
-  view1->Embed(ConnectToApplicationAndGetViewManagerClient());
+  WindowRemovedFromParentObserver observer(window2);
+  window1->Embed(ConnectToApplicationAndGetWindowServerClient());
   EXPECT_TRUE(observer.was_removed());
-  EXPECT_EQ(nullptr, view2->parent());
-  EXPECT_TRUE(view1->children().empty());
+  EXPECT_EQ(nullptr, window2->parent());
+  EXPECT_TRUE(window1->children().empty());
 
   // Run the message loop so the Embed() call above completes. Without this
   // we may end up reconnecting to the test and rerunning the test, which is
@@ -723,10 +737,10 @@
 
 namespace {
 
-class DestroyObserver : public ViewObserver {
+class DestroyObserver : public WindowObserver {
  public:
-  DestroyObserver(ViewManagerTestBase* test,
-                  ViewTreeConnection* connection,
+  DestroyObserver(WindowServerTestBase* test,
+                  WindowTreeConnection* connection,
                   bool* got_destroy)
       : test_(test), got_destroy_(got_destroy) {
     connection->GetRoot()->AddObserver(this);
@@ -734,18 +748,19 @@
   ~DestroyObserver() override {}
 
  private:
-  // Overridden from ViewObserver:
-  void OnViewDestroyed(View* view) override {
+  // Overridden from WindowObserver:
+  void OnWindowDestroyed(Window* window) override {
     *got_destroy_ = true;
-    view->RemoveObserver(this);
+    window->RemoveObserver(this);
 
-    // We should always get OnViewDestroyed() before OnViewManagerDestroyed().
-    EXPECT_FALSE(test_->view_tree_connection_destroyed());
+    // We should always get OnWindowDestroyed() before
+    // OnWindowManagerDestroyed().
+    EXPECT_FALSE(test_->window_tree_connection_destroyed());
 
-    EXPECT_TRUE(ViewManagerTestBase::QuitRunLoop());
+    EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
   }
 
-  ViewManagerTestBase* test_;
+  WindowServerTestBase* test_;
   bool* got_destroy_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(DestroyObserver);
@@ -753,59 +768,59 @@
 
 }  // namespace
 
-// Verifies deleting a View that is the root of another connection notifies
-// observers in the right order (OnViewDestroyed() before
-// OnViewManagerDestroyed()).
-TEST_F(ViewManagerTest, ViewManagerDestroyedAfterRootObserver) {
-  View* embed_view = window_manager()->CreateView();
-  window_manager()->GetRoot()->AddChild(embed_view);
+// Verifies deleting a Window that is the root of another connection notifies
+// observers in the right order (OnWindowDestroyed() before
+// OnWindowManagerDestroyed()).
+TEST_F(WindowServerTest, WindowServerDestroyedAfterRootObserver) {
+  Window* embed_window = window_manager()->CreateWindow();
+  window_manager()->GetRoot()->AddChild(embed_window);
 
-  ViewTreeConnection* embedded_connection = Embed(embed_view).connection;
+  WindowTreeConnection* embedded_connection = Embed(embed_window).connection;
 
   bool got_destroy = false;
   DestroyObserver observer(this, embedded_connection, &got_destroy);
-  // Delete the view |embedded_connection| is embedded in. This is async,
+  // Delete the window |embedded_connection| is embedded in. This is async,
   // but will eventually trigger deleting |embedded_connection|.
-  embed_view->Destroy();
+  embed_window->Destroy();
   EXPECT_TRUE(DoRunLoopWithTimeout());
   EXPECT_TRUE(got_destroy);
 }
 
-// Verifies an embed root sees views created beneath it from another
+// Verifies an embed root sees windows created beneath it from another
 // connection.
-TEST_F(ViewManagerTest, EmbedRootSeesHierarchyChanged) {
-  View* embed_view = window_manager()->CreateView();
-  window_manager()->GetRoot()->AddChild(embed_view);
+TEST_F(WindowServerTest, EmbedRootSeesHierarchyChanged) {
+  Window* embed_window = window_manager()->CreateWindow();
+  window_manager()->GetRoot()->AddChild(embed_window);
 
-  ViewTreeConnection* vm2 =
-      Embed(embed_view, mojo::ViewTree::ACCESS_POLICY_EMBED_ROOT).connection;
-  View* vm2_v1 = vm2->CreateView();
+  WindowTreeConnection* vm2 =
+      Embed(embed_window, mojo::ViewTree::ACCESS_POLICY_EMBED_ROOT).connection;
+  Window* vm2_v1 = vm2->CreateWindow();
   vm2->GetRoot()->AddChild(vm2_v1);
 
-  ViewTreeConnection* vm3 = Embed(vm2_v1).connection;
-  View* vm3_v1 = vm3->CreateView();
+  WindowTreeConnection* vm3 = Embed(vm2_v1).connection;
+  Window* vm3_v1 = vm3->CreateWindow();
   vm3->GetRoot()->AddChild(vm3_v1);
 
   // As |vm2| is an embed root it should get notified about |vm3_v1|.
   ASSERT_TRUE(WaitForTreeSizeToMatch(vm2_v1, 2));
 }
 
-TEST_F(ViewManagerTest, EmbedFromEmbedRoot) {
-  View* embed_view = window_manager()->CreateView();
-  window_manager()->GetRoot()->AddChild(embed_view);
+TEST_F(WindowServerTest, EmbedFromEmbedRoot) {
+  Window* embed_window = window_manager()->CreateWindow();
+  window_manager()->GetRoot()->AddChild(embed_window);
 
-  // Give the connection embedded at |embed_view| embed root powers.
+  // Give the connection embedded at |embed_window| embed root powers.
   const EmbedResult result1 =
-      Embed(embed_view, mojo::ViewTree::ACCESS_POLICY_EMBED_ROOT);
-  ViewTreeConnection* vm2 = result1.connection;
+      Embed(embed_window, mojo::ViewTree::ACCESS_POLICY_EMBED_ROOT);
+  WindowTreeConnection* vm2 = result1.connection;
   EXPECT_EQ(result1.connection_id, vm2->GetConnectionId());
-  View* vm2_v1 = vm2->CreateView();
+  Window* vm2_v1 = vm2->CreateWindow();
   vm2->GetRoot()->AddChild(vm2_v1);
 
   const EmbedResult result2 = Embed(vm2_v1);
-  ViewTreeConnection* vm3 = result2.connection;
+  WindowTreeConnection* vm3 = result2.connection;
   EXPECT_EQ(result2.connection_id, vm3->GetConnectionId());
-  View* vm3_v1 = vm3->CreateView();
+  Window* vm3_v1 = vm3->CreateWindow();
   vm3->GetRoot()->AddChild(vm3_v1);
 
   // Embed from v3, the callback should not get the connection id as vm3 is not
@@ -820,7 +835,7 @@
   // Embed() from vm2 in vm3_v1. This is allowed as vm2 is an embed root, and
   // further the callback should see the connection id.
   ASSERT_EQ(1u, vm2_v1->children().size());
-  View* vm3_v1_in_vm2 = vm2_v1->children()[0];
+  Window* vm3_v1_in_vm2 = vm2_v1->children()[0];
   const EmbedResult result4 = Embed(vm3_v1_in_vm2);
   ASSERT_TRUE(result4.connection);
   EXPECT_EQ(result4.connection_id, result4.connection->GetConnectionId());
diff --git a/components/mus/vm/view_tree_apptest.cc b/components/mus/vm/view_tree_apptest.cc
index 14c812a5..3f34d10 100644
--- a/components/mus/vm/view_tree_apptest.cc
+++ b/components/mus/vm/view_tree_apptest.cc
@@ -316,55 +316,55 @@
     tracker()->OnEmbeddedAppDisconnected(view_id);
   }
   void OnUnembed() override { tracker()->OnUnembed(); }
-  void OnViewBoundsChanged(Id view_id,
-                           RectPtr old_bounds,
-                           RectPtr new_bounds) override {
+  void OnWindowBoundsChanged(Id view_id,
+                             RectPtr old_bounds,
+                             RectPtr new_bounds) override {
     // The bounds of the root may change during startup on Android at random
     // times. As this doesn't matter, and shouldn't impact test exepctations,
     // it is ignored.
     if (view_id == root_view_id_)
       return;
-    tracker()->OnViewBoundsChanged(view_id, old_bounds.Pass(),
-                                   new_bounds.Pass());
+    tracker()->OnWindowBoundsChanged(view_id, old_bounds.Pass(),
+                                     new_bounds.Pass());
   }
-  void OnViewViewportMetricsChanged(ViewportMetricsPtr old_metrics,
-                                    ViewportMetricsPtr new_metrics) override {
+  void OnWindowViewportMetricsChanged(ViewportMetricsPtr old_metrics,
+                                      ViewportMetricsPtr new_metrics) override {
     // Don't track the metrics as they are available at an indeterministic time
     // on Android.
   }
-  void OnViewHierarchyChanged(Id view,
-                              Id new_parent,
-                              Id old_parent,
-                              Array<ViewDataPtr> views) override {
-    tracker()->OnViewHierarchyChanged(view, new_parent, old_parent,
-                                      views.Pass());
+  void OnWindowHierarchyChanged(Id view,
+                                Id new_parent,
+                                Id old_parent,
+                                Array<ViewDataPtr> views) override {
+    tracker()->OnWindowHierarchyChanged(view, new_parent, old_parent,
+                                        views.Pass());
   }
-  void OnViewReordered(Id view_id,
-                       Id relative_view_id,
-                       OrderDirection direction) override {
-    tracker()->OnViewReordered(view_id, relative_view_id, direction);
+  void OnWindowReordered(Id view_id,
+                         Id relative_view_id,
+                         OrderDirection direction) override {
+    tracker()->OnWindowReordered(view_id, relative_view_id, direction);
   }
-  void OnViewDeleted(Id view) override { tracker()->OnViewDeleted(view); }
-  void OnViewVisibilityChanged(uint32_t view, bool visible) override {
-    tracker()->OnViewVisibilityChanged(view, visible);
+  void OnWindowDeleted(Id view) override { tracker()->OnWindowDeleted(view); }
+  void OnWindowVisibilityChanged(uint32_t view, bool visible) override {
+    tracker()->OnWindowVisibilityChanged(view, visible);
   }
-  void OnViewDrawnStateChanged(uint32_t view, bool drawn) override {
-    tracker()->OnViewDrawnStateChanged(view, drawn);
+  void OnWindowDrawnStateChanged(uint32_t view, bool drawn) override {
+    tracker()->OnWindowDrawnStateChanged(view, drawn);
   }
-  void OnViewInputEvent(Id view_id,
-                        EventPtr event,
-                        const Callback<void()>& callback) override {
+  void OnWindowInputEvent(Id view_id,
+                          EventPtr event,
+                          const Callback<void()>& callback) override {
     // Don't log input events as none of the tests care about them and they
     // may come in at random points.
     callback.Run();
   }
-  void OnViewSharedPropertyChanged(uint32_t view,
-                                   const String& name,
-                                   Array<uint8_t> new_data) override {
-    tracker_.OnViewSharedPropertyChanged(view, name, new_data.Pass());
+  void OnWindowSharedPropertyChanged(uint32_t view,
+                                     const String& name,
+                                     Array<uint8_t> new_data) override {
+    tracker_.OnWindowSharedPropertyChanged(view, name, new_data.Pass());
   }
   // TODO(sky): add testing coverage.
-  void OnViewFocused(uint32_t focused_view_id) override {}
+  void OnWindowFocused(uint32_t focused_view_id) override {}
 
   TestChangeTracker tracker_;
 
@@ -534,8 +534,9 @@
     vm_client1_.reset(new TestViewTreeClientImpl(application_impl()));
     vm_client1_->Bind(GetProxy(&tree_client_ptr));
 
-    factory->CreateViewTreeHost(GetProxy(&host_), mojo::ViewTreeHostClientPtr(),
-                                tree_client_ptr.Pass());
+    factory->CreateWindowTreeHost(GetProxy(&host_),
+                                  mojo::ViewTreeHostClientPtr(),
+                                  tree_client_ptr.Pass());
 
     // Next we should get an embed call on the "window manager" client.
     vm_client1_->WaitForIncomingMethodCall();
diff --git a/components/mus/vm/view_tree_host_impl.cc b/components/mus/vm/view_tree_host_impl.cc
index 6dc9c3e..5fdbdc57 100644
--- a/components/mus/vm/view_tree_host_impl.cc
+++ b/components/mus/vm/view_tree_host_impl.cc
@@ -111,9 +111,9 @@
       connection_manager_->GetConnectionWithRoot(target->id());
   if (!connection)
     connection = connection_manager_->GetConnection(target->id().connection_id);
-  connection->client()->OnViewInputEvent(ViewIdToTransportId(target->id()),
-                                         event.Pass(),
-                                         base::Bind(&base::DoNothing));
+  connection->client()->OnWindowInputEvent(ViewIdToTransportId(target->id()),
+                                           event.Pass(),
+                                           base::Bind(&base::DoNothing));
 }
 
 void ViewTreeHostImpl::SetSize(mojo::SizePtr size) {
diff --git a/components/mus/vm/view_tree_impl.cc b/components/mus/vm/view_tree_impl.cc
index 794f56b9..40e2c07 100644
--- a/components/mus/vm/view_tree_impl.cc
+++ b/components/mus/vm/view_tree_impl.cc
@@ -181,16 +181,17 @@
                                             bool originated_change) {
   if (originated_change || !IsViewKnown(view))
     return;
-  client()->OnViewBoundsChanged(ViewIdToTransportId(view->id()),
-                                Rect::From(old_bounds), Rect::From(new_bounds));
+  client()->OnWindowBoundsChanged(ViewIdToTransportId(view->id()),
+                                  Rect::From(old_bounds),
+                                  Rect::From(new_bounds));
 }
 
 void ViewTreeImpl::ProcessViewportMetricsChanged(
     const mojo::ViewportMetrics& old_metrics,
     const mojo::ViewportMetrics& new_metrics,
     bool originated_change) {
-  client()->OnViewViewportMetricsChanged(old_metrics.Clone(),
-                                         new_metrics.Clone());
+  client()->OnWindowViewportMetricsChanged(old_metrics.Clone(),
+                                           new_metrics.Clone());
 }
 
 void ViewTreeImpl::ProcessWillChangeViewHierarchy(const ServerView* view,
@@ -220,8 +221,8 @@
   if (new_data)
     data = Array<uint8_t>::From(*new_data);
 
-  client()->OnViewSharedPropertyChanged(ViewIdToTransportId(view->id()),
-                                        String(name), data.Pass());
+  client()->OnWindowSharedPropertyChanged(ViewIdToTransportId(view->id()),
+                                          String(name), data.Pass());
 }
 
 void ViewTreeImpl::ProcessViewHierarchyChanged(const ServerView* view,
@@ -249,7 +250,7 @@
     GetUnknownViewsFrom(view, &to_send);
   const ViewId new_parent_id(new_parent ? new_parent->id() : ViewId());
   const ViewId old_parent_id(old_parent ? old_parent->id() : ViewId());
-  client()->OnViewHierarchyChanged(
+  client()->OnWindowHierarchyChanged(
       ViewIdToTransportId(view->id()), ViewIdToTransportId(new_parent_id),
       ViewIdToTransportId(old_parent_id), ViewsToViewDatas(to_send));
   connection_manager_->OnConnectionMessagedClient(id_);
@@ -262,9 +263,9 @@
   if (originated_change || !IsViewKnown(view) || !IsViewKnown(relative_view))
     return;
 
-  client()->OnViewReordered(ViewIdToTransportId(view->id()),
-                            ViewIdToTransportId(relative_view->id()),
-                            direction);
+  client()->OnWindowReordered(ViewIdToTransportId(view->id()),
+                              ViewIdToTransportId(relative_view->id()),
+                              direction);
 }
 
 void ViewTreeImpl::ProcessViewDeleted(const ViewId& view,
@@ -281,7 +282,7 @@
     return;
 
   if (in_known) {
-    client()->OnViewDeleted(ViewIdToTransportId(view));
+    client()->OnWindowDeleted(ViewIdToTransportId(view));
     connection_manager_->OnConnectionMessagedClient(id_);
   }
 }
@@ -292,8 +293,8 @@
     return;
 
   if (IsViewKnown(view)) {
-    client()->OnViewVisibilityChanged(ViewIdToTransportId(view->id()),
-                                      !view->visible());
+    client()->OnWindowVisibilityChanged(ViewIdToTransportId(view->id()),
+                                        !view->visible());
     return;
   }
 
@@ -314,8 +315,8 @@
   const ServerView* view =
       new_focused_view ? access_policy_->GetViewForFocusChange(new_focused_view)
                        : nullptr;
-  client()->OnViewFocused(view ? ViewIdToTransportId(view->id())
-                               : ViewIdToTransportId(ViewId()));
+  client()->OnWindowFocused(view ? ViewIdToTransportId(view->id())
+                                 : ViewIdToTransportId(ViewId()));
 }
 
 bool ViewTreeImpl::IsViewKnown(const ServerView* view) const {
@@ -391,7 +392,7 @@
     return;
 
   client()->OnUnembed();
-  client()->OnViewDeleted(ViewIdToTransportId(root_id));
+  client()->OnWindowDeleted(ViewIdToTransportId(root_id));
   connection_manager_->OnConnectionMessagedClient(id_);
 
   // This connection no longer knows about the view. Unparent any views that
@@ -458,8 +459,8 @@
   const ServerView* root = GetView(*root_);
   DCHECK(root);
   if (view->Contains(root) && (new_drawn_value != root->IsDrawn())) {
-    client()->OnViewDrawnStateChanged(ViewIdToTransportId(root->id()),
-                                      new_drawn_value);
+    client()->OnWindowDrawnStateChanged(ViewIdToTransportId(root->id()),
+                                        new_drawn_value);
   }
 }
 
@@ -609,7 +610,7 @@
                                   mojo::InterfaceRequest<mojo::Surface> surface,
                                   mojo::SurfaceClientPtr client) {
   ServerView* view = GetView(ViewIdFromTransportId(view_id));
-  const bool success = view && access_policy_->CanSetViewSurfaceId(view);
+  const bool success = view && access_policy_->CanSetWindowSurfaceId(view);
   if (!success)
     return;
   view->Bind(surface.Pass(), client.Pass());
diff --git a/components/mus/vm/view_tree_unittest.cc b/components/mus/vm/view_tree_unittest.cc
index a775d039..352625c 100644
--- a/components/mus/vm/view_tree_unittest.cc
+++ b/components/mus/vm/view_tree_unittest.cc
@@ -61,47 +61,50 @@
     tracker_.OnEmbeddedAppDisconnected(view);
   }
   void OnUnembed() override { tracker_.OnUnembed(); }
-  void OnViewBoundsChanged(uint32_t view,
-                           mojo::RectPtr old_bounds,
-                           mojo::RectPtr new_bounds) override {
-    tracker_.OnViewBoundsChanged(view, old_bounds.Pass(), new_bounds.Pass());
+  void OnWindowBoundsChanged(uint32_t view,
+                             mojo::RectPtr old_bounds,
+                             mojo::RectPtr new_bounds) override {
+    tracker_.OnWindowBoundsChanged(view, old_bounds.Pass(), new_bounds.Pass());
   }
-  void OnViewViewportMetricsChanged(
+  void OnWindowViewportMetricsChanged(
       mojo::ViewportMetricsPtr old_metrics,
       mojo::ViewportMetricsPtr new_metrics) override {
-    tracker_.OnViewViewportMetricsChanged(old_metrics.Pass(),
-                                          new_metrics.Pass());
+    tracker_.OnWindowViewportMetricsChanged(old_metrics.Pass(),
+                                            new_metrics.Pass());
   }
-  void OnViewHierarchyChanged(uint32_t view,
-                              uint32_t new_parent,
-                              uint32_t old_parent,
-                              Array<ViewDataPtr> views) override {
-    tracker_.OnViewHierarchyChanged(view, new_parent, old_parent, views.Pass());
+  void OnWindowHierarchyChanged(uint32_t view,
+                                uint32_t new_parent,
+                                uint32_t old_parent,
+                                Array<ViewDataPtr> views) override {
+    tracker_.OnWindowHierarchyChanged(view, new_parent, old_parent,
+                                      views.Pass());
   }
-  void OnViewReordered(uint32_t view_id,
-                       uint32_t relative_view_id,
-                       mojo::OrderDirection direction) override {
-    tracker_.OnViewReordered(view_id, relative_view_id, direction);
+  void OnWindowReordered(uint32_t view_id,
+                         uint32_t relative_view_id,
+                         mojo::OrderDirection direction) override {
+    tracker_.OnWindowReordered(view_id, relative_view_id, direction);
   }
-  void OnViewDeleted(uint32_t view) override { tracker_.OnViewDeleted(view); }
-  void OnViewVisibilityChanged(uint32_t view, bool visible) override {
-    tracker_.OnViewVisibilityChanged(view, visible);
+  void OnWindowDeleted(uint32_t view) override {
+    tracker_.OnWindowDeleted(view);
   }
-  void OnViewDrawnStateChanged(uint32_t view, bool drawn) override {
-    tracker_.OnViewDrawnStateChanged(view, drawn);
+  void OnWindowVisibilityChanged(uint32_t view, bool visible) override {
+    tracker_.OnWindowVisibilityChanged(view, visible);
   }
-  void OnViewSharedPropertyChanged(uint32_t view,
-                                   const String& name,
-                                   Array<uint8_t> new_data) override {
-    tracker_.OnViewSharedPropertyChanged(view, name, new_data.Pass());
+  void OnWindowDrawnStateChanged(uint32_t view, bool drawn) override {
+    tracker_.OnWindowDrawnStateChanged(view, drawn);
   }
-  void OnViewInputEvent(uint32_t view,
-                        mojo::EventPtr event,
-                        const mojo::Callback<void()>& callback) override {
-    tracker_.OnViewInputEvent(view, event.Pass());
+  void OnWindowSharedPropertyChanged(uint32_t view,
+                                     const String& name,
+                                     Array<uint8_t> new_data) override {
+    tracker_.OnWindowSharedPropertyChanged(view, name, new_data.Pass());
   }
-  void OnViewFocused(uint32_t focused_view_id) override {
-    tracker_.OnViewFocused(focused_view_id);
+  void OnWindowInputEvent(uint32_t view,
+                          mojo::EventPtr event,
+                          const mojo::Callback<void()>& callback) override {
+    tracker_.OnWindowInputEvent(view, event.Pass());
+  }
+  void OnWindowFocused(uint32_t focused_view_id) override {
+    tracker_.OnWindowFocused(focused_view_id);
   }
 
   TestChangeTracker tracker_;
diff --git a/components/mus/vm/window_manager_access_policy.cc b/components/mus/vm/window_manager_access_policy.cc
index a7da4972..6cfb6202 100644
--- a/components/mus/vm/window_manager_access_policy.cc
+++ b/components/mus/vm/window_manager_access_policy.cc
@@ -61,7 +61,7 @@
          (view->GetRoot() == view);
 }
 
-bool WindowManagerAccessPolicy::CanSetViewSurfaceId(
+bool WindowManagerAccessPolicy::CanSetWindowSurfaceId(
     const ServerView* view) const {
   if (delegate_->IsViewRootOfAnotherConnectionForAccessPolicy(view))
     return false;
diff --git a/components/mus/vm/window_manager_access_policy.h b/components/mus/vm/window_manager_access_policy.h
index 78f9513..b08946b6 100644
--- a/components/mus/vm/window_manager_access_policy.h
+++ b/components/mus/vm/window_manager_access_policy.h
@@ -30,7 +30,7 @@
   bool CanDescendIntoViewForViewTree(const ServerView* view) const override;
   bool CanEmbed(const ServerView* view, uint32_t policy_bitmask) const override;
   bool CanChangeViewVisibility(const ServerView* view) const override;
-  bool CanSetViewSurfaceId(const ServerView* view) const override;
+  bool CanSetWindowSurfaceId(const ServerView* view) const override;
   bool CanSetViewBounds(const ServerView* view) const override;
   bool CanSetViewProperties(const ServerView* view) const override;
   bool CanSetViewTextInputState(const ServerView* view) const override;
diff --git a/components/pdf_viewer/pdf_viewer.cc b/components/pdf_viewer/pdf_viewer.cc
index 01336a3d..b1c11c7b 100644
--- a/components/pdf_viewer/pdf_viewer.cc
+++ b/components/pdf_viewer/pdf_viewer.cc
@@ -7,11 +7,11 @@
 #include "base/containers/hash_tables.h"
 #include "base/memory/scoped_ptr.h"
 #include "components/mus/public/cpp/types.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_observer.h"
-#include "components/mus/public/cpp/view_surface.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_surface.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
 #include "components/mus/public/interfaces/compositor_frame.mojom.h"
 #include "components/mus/public/interfaces/gpu.mojom.h"
 #include "components/mus/public/interfaces/surface_id.mojom.h"
@@ -58,7 +58,7 @@
 // BitmapUploader is useful if you want to draw a bitmap or color in a View.
 class BitmapUploader : public mojo::SurfaceClient {
  public:
-  explicit BitmapUploader(mus::View* view)
+  explicit BitmapUploader(mus::Window* view)
       : view_(view),
         color_(g_transparent_color),
         width_(0),
@@ -289,9 +289,9 @@
     }
   }
 
-  mus::View* view_;
+  mus::Window* view_;
   mojo::GpuPtr gpu_service_;
-  scoped_ptr<mus::ViewSurface> surface_;
+  scoped_ptr<mus::WindowSurface> surface_;
   MojoGLES2Context gles2_context_;
 
   mojo::Size size_;
@@ -311,7 +311,7 @@
 
 class EmbedderData {
  public:
-  EmbedderData(mojo::Shell* shell, mus::View* root) : bitmap_uploader_(root) {
+  EmbedderData(mojo::Shell* shell, mus::Window* root) : bitmap_uploader_(root) {
     bitmap_uploader_.Init(shell);
     bitmap_uploader_.SetColor(g_background_color);
   }
@@ -325,8 +325,8 @@
 };
 
 class PDFView : public mojo::ApplicationDelegate,
-                public mus::ViewTreeDelegate,
-                public mus::ViewObserver,
+                public mus::WindowTreeDelegate,
+                public mus::WindowObserver,
                 public mojo::InterfaceFactory<mojo::ViewTreeClient> {
  public:
   PDFView(mojo::InterfaceRequest<mojo::Application> request,
@@ -354,8 +354,8 @@
     return true;
   }
 
-  // Overridden from ViewTreeDelegate:
-  void OnEmbed(mus::View* root) override {
+  // Overridden from WindowTreeDelegate:
+  void OnEmbed(mus::Window* root) override {
     DCHECK(embedder_for_roots_.find(root) == embedder_for_roots_.end());
     root->AddObserver(this);
     EmbedderData* embedder_data = new EmbedderData(app_.shell(), root);
@@ -363,17 +363,18 @@
     DrawBitmap(embedder_data);
   }
 
-  void OnConnectionLost(mus::ViewTreeConnection* connection) override {}
+  void OnConnectionLost(mus::WindowTreeConnection* connection) override {}
 
-  // Overridden from ViewObserver:
-  void OnViewBoundsChanged(mus::View* view,
-                           const mojo::Rect& old_bounds,
-                           const mojo::Rect& new_bounds) override {
+  // Overridden from WindowObserver:
+  void OnWindowBoundsChanged(mus::Window* view,
+                             const mojo::Rect& old_bounds,
+                             const mojo::Rect& new_bounds) override {
     DCHECK(embedder_for_roots_.find(view) != embedder_for_roots_.end());
     DrawBitmap(embedder_for_roots_[view]);
   }
 
-  void OnViewInputEvent(mus::View* view, const mojo::EventPtr& event) override {
+  void OnWindowInputEvent(mus::Window* view,
+                          const mojo::EventPtr& event) override {
     DCHECK(embedder_for_roots_.find(view) != embedder_for_roots_.end());
     if (event->key_data &&
         (event->action != mojo::EVENT_TYPE_KEY_PRESSED ||
@@ -400,7 +401,7 @@
     }
   }
 
-  void OnViewDestroyed(mus::View* view) override {
+  void OnWindowDestroyed(mus::Window* view) override {
     DCHECK(embedder_for_roots_.find(view) != embedder_for_roots_.end());
     const auto& it = embedder_for_roots_.find(view);
     DCHECK(it != embedder_for_roots_.end());
@@ -414,9 +415,9 @@
   void Create(
       mojo::ApplicationConnection* connection,
       mojo::InterfaceRequest<mojo::ViewTreeClient> request) override {
-    mus::ViewTreeConnection::Create(
+    mus::WindowTreeConnection::Create(
         this, request.Pass(),
-        mus::ViewTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
+        mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
   }
 
   void DrawBitmap(EmbedderData* embedder_data) {
@@ -465,7 +466,7 @@
   int current_page_;
   int page_count_;
   FPDF_DOCUMENT doc_;
-  std::map<mus::View*, EmbedderData*> embedder_for_roots_;
+  std::map<mus::Window*, EmbedderData*> embedder_for_roots_;
 
   DISALLOW_COPY_AND_ASSIGN(PDFView);
 };
diff --git a/components/plugins/renderer/loadable_plugin_placeholder.cc b/components/plugins/renderer/loadable_plugin_placeholder.cc
index 40c4a5a..ed0c1a2 100644
--- a/components/plugins/renderer/loadable_plugin_placeholder.cc
+++ b/components/plugins/renderer/loadable_plugin_placeholder.cc
@@ -105,6 +105,7 @@
   if (!new_plugin)
     return;
   blink::WebPluginContainer* container = plugin()->container();
+  CHECK(container->plugin() == plugin());
   // Set the new plugin on the container before initializing it.
   container->setPlugin(new_plugin);
   // Save the element in case the plugin is removed from the page during
diff --git a/components/policy/BUILD.gn b/components/policy/BUILD.gn
index 7b5cca1..b6274b8b 100644
--- a/components/policy/BUILD.gn
+++ b/components/policy/BUILD.gn
@@ -24,35 +24,35 @@
 # dependencies (GN will do the right thing without this extra target).
 if (is_component_build) {
   component("policy_component") {
-    deps = [
+    public_deps = [
       "//components/policy/core/browser",
       "//components/policy/core/common",
     ]
   }
   group("policy_component_browser") {
-    deps = [
+    public_deps = [
       ":policy_component",
     ]
   }
   group("policy_component_common") {
-    deps = [
+    public_deps = [
       ":policy_component",
     ]
   }
 } else {  # Compile to separate libraries.
   group("policy_component") {
-    deps = [
+    public_deps = [
       ":policy_component_browser",
       ":policy_component_common",
     ]
   }
   component("policy_component_browser") {
-    deps = [
+    public_deps = [
       "//components/policy/core/browser",
     ]
   }
   component("policy_component_common") {
-    deps = [
+    public_deps = [
       "//components/policy/core/common",
     ]
   }
diff --git a/components/resource_provider/public/cpp/resource_loader.cc b/components/resource_provider/public/cpp/resource_loader.cc
index 3b6ea168..8b1c116 100644
--- a/components/resource_provider/public/cpp/resource_loader.cc
+++ b/components/resource_provider/public/cpp/resource_loader.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/files/file.h"
+#include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/application/public/cpp/connect.h"
 #include "mojo/application/public/interfaces/service_provider.mojom.h"
 #include "mojo/application/public/interfaces/shell.mojom.h"
@@ -23,17 +24,12 @@
 }
 }
 
-ResourceLoader::ResourceLoader(mojo::Shell* shell,
+ResourceLoader::ResourceLoader(mojo::ApplicationImpl* app,
                                const std::set<std::string>& paths)
     : loaded_(false), did_block_(false) {
   mojo::URLRequestPtr request(mojo::URLRequest::New());
   request->url = mojo::String::From("mojo:resource_provider");
-  mojo::ServiceProviderPtr resource_provider_service_provider;
-  shell->ConnectToApplication(
-      request.Pass(), GetProxy(&resource_provider_service_provider), nullptr,
-      nullptr, mojo::Shell::ConnectToApplicationCallback());
-  mojo::ConnectToService(resource_provider_service_provider.get(),
-                         &resource_provider_);
+  app->ConnectToService(request.Pass(), &resource_provider_);
   std::vector<std::string> paths_vector(paths.begin(), paths.end());
   resource_provider_->GetResources(
       mojo::Array<mojo::String>::From(paths_vector),
diff --git a/components/resource_provider/public/cpp/resource_loader.h b/components/resource_provider/public/cpp/resource_loader.h
index fae6655f..2b055aa 100644
--- a/components/resource_provider/public/cpp/resource_loader.h
+++ b/components/resource_provider/public/cpp/resource_loader.h
@@ -22,7 +22,7 @@
 }
 
 namespace mojo {
-class Shell;
+class ApplicationImpl;
 }
 
 namespace resource_provider {
@@ -33,7 +33,8 @@
 // have been obtained.
 class ResourceLoader {
  public:
-  ResourceLoader(mojo::Shell* shell, const std::set<std::string>& paths);
+  ResourceLoader(mojo::ApplicationImpl* app,
+                 const std::set<std::string>& paths);
   ~ResourceLoader();
 
   // Uses WaitForIncomingMessage() to block until the results are available, or
diff --git a/components/resource_provider/resource_provider_apptest.cc b/components/resource_provider/resource_provider_apptest.cc
index 5484368..c1f0d07 100644
--- a/components/resource_provider/resource_provider_apptest.cc
+++ b/components/resource_provider/resource_provider_apptest.cc
@@ -56,7 +56,7 @@
   // resources are returned. The return map maps from the path to the contents
   // of the file at the specified path.
   ResourceContentsMap GetResources(const std::set<std::string>& paths) {
-    ResourceLoader loader(application_impl()->shell(), paths);
+    ResourceLoader loader(application_impl(), paths);
     loader.BlockUntilLoaded();
 
     // Load the contents of each of the handles.
diff --git a/components/test_runner/BUILD.gn b/components/test_runner/BUILD.gn
index fec5ecd..3c35927 100644
--- a/components/test_runner/BUILD.gn
+++ b/components/test_runner/BUILD.gn
@@ -27,6 +27,8 @@
     "event_sender.h",
     "gamepad_controller.cc",
     "gamepad_controller.h",
+    "gc_controller.cc",
+    "gc_controller.h",
     "mock_color_chooser.cc",
     "mock_color_chooser.h",
     "mock_constraints.cc",
diff --git a/components/test_runner/event_sender.cc b/components/test_runner/event_sender.cc
index 17a45cf..958fadd6 100644
--- a/components/test_runner/event_sender.cc
+++ b/components/test_runner/event_sender.cc
@@ -96,6 +96,12 @@
 #else
     return WebInputEvent::ControlKey;
 #endif
+  } else if (!strcmp(characters, "accessKey")) {
+#ifdef __APPLE__
+    return WebInputEvent::AltKey | WebInputEvent::ControlKey;
+#else
+    return WebInputEvent::AltKey;
+#endif
   } else if (!strcmp(characters, "leftButton")) {
     return WebInputEvent::LeftButtonDown;
   } else if (!strcmp(characters, "middleButton")) {
diff --git a/content/shell/renderer/layout_test/gc_controller.cc b/components/test_runner/gc_controller.cc
similarity index 95%
rename from content/shell/renderer/layout_test/gc_controller.cc
rename to components/test_runner/gc_controller.cc
index 9741e2b..7d4c85a 100644
--- a/content/shell/renderer/layout_test/gc_controller.cc
+++ b/components/test_runner/gc_controller.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/shell/renderer/layout_test/gc_controller.h"
+#include "components/test_runner/gc_controller.h"
 
 #include "gin/arguments.h"
 #include "gin/handle.h"
@@ -11,7 +11,7 @@
 #include "third_party/WebKit/public/web/WebKit.h"
 #include "v8/include/v8.h"
 
-namespace content {
+namespace test_runner {
 
 gin::WrapperInfo GCController::kWrapperInfo = {gin::kEmbedderNativeGin};
 
@@ -69,4 +69,4 @@
       v8::Isolate::kMinorGarbageCollection);
 }
 
-}  // namespace content
+}  // namespace test_runner
diff --git a/content/shell/renderer/layout_test/gc_controller.h b/components/test_runner/gc_controller.h
similarity index 77%
rename from content/shell/renderer/layout_test/gc_controller.h
rename to components/test_runner/gc_controller.h
index 4485c1d..2fce5bc 100644
--- a/content/shell/renderer/layout_test/gc_controller.h
+++ b/components/test_runner/gc_controller.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_SHELL_RENDERER_LAYOUT_TEST_GC_CONTROLLER_H_
-#define CONTENT_SHELL_RENDERER_LAYOUT_TEST_GC_CONTROLLER_H_
+#ifndef COMPONENTS_TEST_RUNNER_GC_CONTROLLER_H_
+#define COMPONENTS_TEST_RUNNER_GC_CONTROLLER_H_
 
 #include "base/basictypes.h"
 #include "gin/wrappable.h"
@@ -16,7 +16,7 @@
 class Arguments;
 }
 
-namespace content {
+namespace test_runner {
 
 class GCController : public gin::Wrappable<GCController> {
  public:
@@ -38,6 +38,6 @@
   DISALLOW_COPY_AND_ASSIGN(GCController);
 };
 
-}  // namespace content
+}  // namespace test_runner
 
-#endif  // CONTENT_SHELL_RENDERER_LAYOUT_TEST_GC_CONTROLLER_H_
+#endif  // COMPONENTS_TEST_RUNNER_GC_CONTROLLER_H_
diff --git a/components/test_runner/test_interfaces.cc b/components/test_runner/test_interfaces.cc
index 614b679..0339ad1 100644
--- a/components/test_runner/test_interfaces.cc
+++ b/components/test_runner/test_interfaces.cc
@@ -15,6 +15,7 @@
 #include "components/test_runner/app_banner_client.h"
 #include "components/test_runner/event_sender.h"
 #include "components/test_runner/gamepad_controller.h"
+#include "components/test_runner/gc_controller.h"
 #include "components/test_runner/test_runner.h"
 #include "components/test_runner/text_input_controller.h"
 #include "components/test_runner/web_test_proxy.h"
@@ -79,6 +80,7 @@
     gamepad_controller_->Install(frame);
   text_input_controller_->Install(frame);
   test_runner_->Install(frame);
+  GCController::Install(frame);
 }
 
 void TestInterfaces::ResetTestHelperControllers() {
diff --git a/components/test_runner/test_runner.gyp b/components/test_runner/test_runner.gyp
index 36e166d..00d9033e6 100644
--- a/components/test_runner/test_runner.gyp
+++ b/components/test_runner/test_runner.gyp
@@ -54,6 +54,8 @@
         'event_sender.h',
         'gamepad_controller.cc',
         'gamepad_controller.h',
+        'gc_controller.cc',
+        'gc_controller.h',
         'mock_color_chooser.cc',
         'mock_color_chooser.h',
         'mock_constraints.cc',
diff --git a/components/web_view/frame.cc b/components/web_view/frame.cc
index 29a22c1..9cc91631 100644
--- a/components/web_view/frame.cc
+++ b/components/web_view/frame.cc
@@ -10,8 +10,8 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/stl_util.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_property.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_property.h"
 #include "components/web_view/frame_tree.h"
 #include "components/web_view/frame_tree_delegate.h"
 #include "components/web_view/frame_user_data.h"
@@ -20,14 +20,14 @@
 #include "mojo/common/url_type_converters.h"
 #include "url/gurl.h"
 
-using mus::View;
+using mus::Window;
 
-DECLARE_VIEW_PROPERTY_TYPE(web_view::Frame*);
+DECLARE_WINDOW_PROPERTY_TYPE(web_view::Frame*);
 
 namespace web_view {
 
 // Used to find the Frame associated with a View.
-DEFINE_LOCAL_VIEW_PROPERTY_KEY(Frame*, kFrame, nullptr);
+DEFINE_LOCAL_WINDOW_PROPERTY_KEY(Frame*, kFrame, nullptr);
 
 namespace {
 
@@ -52,7 +52,7 @@
 };
 
 Frame::Frame(FrameTree* tree,
-             View* view,
+             Window* view,
              uint32_t frame_id,
              uint32_t app_id,
              ViewOwnership view_ownership,
@@ -96,7 +96,8 @@
 
 void Frame::Init(Frame* parent,
                  mojo::ViewTreeClientPtr view_tree_client,
-                 mojo::InterfaceRequest<mojom::Frame> frame_request) {
+                 mojo::InterfaceRequest<mojom::Frame> frame_request,
+                 base::TimeTicks navigation_start_time) {
   {
     // Set the FrameClient to null so that we don't notify the client of the
     // add before OnConnect().
@@ -110,7 +111,7 @@
                                      ? ClientType::NEW_CHILD_FRAME
                                      : ClientType::EXISTING_FRAME_NEW_APP;
   InitClient(client_type, nullptr, view_tree_client.Pass(),
-             frame_request.Pass());
+             frame_request.Pass(), navigation_start_time);
 
   tree_->delegate_->DidCreateFrame(this);
 
@@ -119,7 +120,7 @@
 }
 
 // static
-Frame* Frame::FindFirstFrameAncestor(View* view) {
+Frame* Frame::FindFirstFrameAncestor(Window* view) {
   while (view && !view->GetLocalProperty(kFrame))
     view = view->parent();
   return view ? view->GetLocalProperty(kFrame) : nullptr;
@@ -190,7 +191,8 @@
 void Frame::InitClient(ClientType client_type,
                        scoped_ptr<FrameUserDataAndBinding> data_and_binding,
                        mojo::ViewTreeClientPtr view_tree_client,
-                       mojo::InterfaceRequest<mojom::Frame> frame_request) {
+                       mojo::InterfaceRequest<mojom::Frame> frame_request,
+                       base::TimeTicks navigation_start_time) {
   if (client_type == ClientType::EXISTING_FRAME_NEW_APP &&
       view_tree_client.get()) {
     embedded_connection_id_ = kInvalidConnectionId;
@@ -210,6 +212,7 @@
     frame_client_->OnConnect(
         nullptr, tree_->change_id(), id_, mojom::VIEW_CONNECT_TYPE_USE_NEW,
         mojo::Array<mojom::FrameDataPtr>(),
+        navigation_start_time.ToInternalValue(),
         base::Bind(&OnConnectAck, base::Passed(&data_and_binding)));
   } else {
     std::vector<const Frame*> frames;
@@ -229,7 +232,7 @@
         client_type == ClientType::EXISTING_FRAME_SAME_APP
             ? mojom::VIEW_CONNECT_TYPE_USE_EXISTING
             : mojom::VIEW_CONNECT_TYPE_USE_NEW,
-        array.Pass(),
+        array.Pass(), navigation_start_time.ToInternalValue(),
         base::Bind(&OnConnectAck, base::Passed(&data_and_binding)));
     tree_->delegate_->DidStartNavigation(this);
 
@@ -248,7 +251,8 @@
 void Frame::ChangeClient(mojom::FrameClient* frame_client,
                          scoped_ptr<FrameUserData> user_data,
                          mojo::ViewTreeClientPtr view_tree_client,
-                         uint32_t app_id) {
+                         uint32_t app_id,
+                         base::TimeTicks navigation_start_time) {
   while (!children_.empty())
     delete children_[0];
 
@@ -273,7 +277,7 @@
   app_id_ = app_id;
 
   InitClient(client_type, data_and_binding.Pass(), view_tree_client.Pass(),
-             nullptr);
+             nullptr, navigation_start_time);
 }
 
 void Frame::OnEmbedAck(bool success, mus::ConnectionSpecificId connection_id) {
@@ -286,16 +290,18 @@
 void Frame::OnWillNavigateAck(mojom::FrameClient* frame_client,
                               scoped_ptr<FrameUserData> user_data,
                               mojo::ViewTreeClientPtr view_tree_client,
-                              uint32 app_id) {
+                              uint32 app_id,
+                              base::TimeTicks navigation_start_time) {
   DCHECK(waiting_for_on_will_navigate_ack_);
   DVLOG(2) << "Frame::OnWillNavigateAck id=" << id_;
   waiting_for_on_will_navigate_ack_ = false;
-  ChangeClient(frame_client, user_data.Pass(), view_tree_client.Pass(), app_id);
+  ChangeClient(frame_client, user_data.Pass(), view_tree_client.Pass(), app_id,
+               navigation_start_time);
   if (pending_navigate_.get())
     StartNavigate(pending_navigate_.Pass());
 }
 
-void Frame::SetView(mus::View* view) {
+void Frame::SetView(mus::Window* view) {
   DCHECK(!view_);
   DCHECK_EQ(id_, view->id());
   view_ = view;
@@ -353,13 +359,16 @@
   DVLOG(2) << "Frame::StartNavigate id=" << id_ << " url=" << request->url;
 
   const GURL requested_url(request->url);
+  base::TimeTicks navigation_start_time =
+      base::TimeTicks::FromInternalValue(request->originating_time_ticks);
   tree_->delegate_->CanNavigateFrame(
-      this, request.Pass(),
-      base::Bind(&Frame::OnCanNavigateFrame,
-                 navigate_weak_ptr_factory_.GetWeakPtr(), requested_url));
+      this, request.Pass(), base::Bind(&Frame::OnCanNavigateFrame,
+                                       navigate_weak_ptr_factory_.GetWeakPtr(),
+                                       requested_url, navigation_start_time));
 }
 
 void Frame::OnCanNavigateFrame(const GURL& url,
+                               base::TimeTicks navigation_start_time,
                                uint32_t app_id,
                                mojom::FrameClient* frame_client,
                                scoped_ptr<FrameUserData> user_data,
@@ -372,14 +381,17 @@
     // and ends up reusing it).
     DCHECK(!view_tree_client.get());
     ChangeClient(frame_client, user_data.Pass(), view_tree_client.Pass(),
-                 app_id);
+                 app_id, navigation_start_time);
   } else {
     waiting_for_on_will_navigate_ack_ = true;
     DCHECK(view_tree_client.get());
     // TODO(sky): url isn't correct here, it should be a security origin.
-    frame_client_->OnWillNavigate(url.spec(), base::Bind(
-        &Frame::OnWillNavigateAck, base::Unretained(this), frame_client,
-        base::Passed(&user_data), base::Passed(&view_tree_client), app_id));
+    frame_client_->OnWillNavigate(
+        url.spec(),
+        base::Bind(&Frame::OnWillNavigateAck, base::Unretained(this),
+                   frame_client, base::Passed(&user_data),
+                   base::Passed(&view_tree_client), app_id,
+                   navigation_start_time));
   }
 }
 
@@ -430,7 +442,7 @@
   }
 }
 
-void Frame::OnViewDestroying(mus::View* view) {
+void Frame::OnWindowDestroying(mus::Window* view) {
   if (parent_)
     parent_->Remove(this);
 
@@ -447,15 +459,16 @@
   delete this;
 }
 
-void Frame::OnViewEmbeddedAppDisconnected(mus::View* view) {
-  // See FrameTreeDelegate::OnViewEmbeddedAppDisconnected() for details of when
+void Frame::OnWindowEmbeddedAppDisconnected(mus::Window* view) {
+  // See FrameTreeDelegate::OnWindowEmbeddedAppDisconnected() for details of
+  // when
   // this happens.
   //
   // Currently we have no way to distinguish between the cases that lead to this
   // being called, so we assume we can continue on. Continuing on is important
   // for html as it's entirely possible for a page to create a frame, navigate
   // to a bogus url and expect the frame to still exist.
-  tree_->delegate_->OnViewEmbeddedInFrameDisconnected(this);
+  tree_->delegate_->OnWindowEmbeddedInFrameDisconnected(this);
 }
 
 void Frame::PostMessageEventToFrame(uint32_t target_frame_id,
diff --git a/components/web_view/frame.h b/components/web_view/frame.h
index 899781b1..38e10783 100644
--- a/components/web_view/frame.h
+++ b/components/web_view/frame.h
@@ -10,8 +10,9 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
 #include "components/mus/public/cpp/types.h"
-#include "components/mus/public/cpp/view_observer.h"
+#include "components/mus/public/cpp/window_observer.h"
 #include "components/web_view/public/interfaces/frame.mojom.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
 
@@ -51,13 +52,13 @@
 // the argument |reuse_existing_view| supplied to OnConnect(). Typically the id
 // is that of content handler id, but this is left up to the FrameTreeDelegate
 // to decide.
-class Frame : public mus::ViewObserver, public mojom::Frame {
+class Frame : public mus::WindowObserver, public mojom::Frame {
  public:
   using ClientPropertyMap = std::map<std::string, std::vector<uint8_t>>;
   using FindCallback = mojo::Callback<void(bool)>;
 
   Frame(FrameTree* tree,
-        mus::View* view,
+        mus::Window* view,
         uint32_t frame_id,
         uint32_t app_id,
         ViewOwnership view_ownership,
@@ -68,21 +69,22 @@
 
   void Init(Frame* parent,
             mojo::ViewTreeClientPtr view_tree_client,
-            mojo::InterfaceRequest<mojom::Frame> frame_request);
+            mojo::InterfaceRequest<mojom::Frame> frame_request,
+            base::TimeTicks navigation_start_time);
 
   // Walks the View tree starting at |view| going up returning the first
   // Frame that is associated with |view|. For example, if |view|
   // has a Frame associated with it, then that is returned. Otherwise
   // this checks view->parent() and so on.
-  static Frame* FindFirstFrameAncestor(mus::View* view);
+  static Frame* FindFirstFrameAncestor(mus::Window* view);
 
   FrameTree* tree() { return tree_; }
 
   Frame* parent() { return parent_; }
   const Frame* parent() const { return parent_; }
 
-  mus::View* view() { return view_; }
-  const mus::View* view() const { return view_; }
+  mus::Window* view() { return view_; }
+  const mus::Window* view() const { return view_; }
 
   uint32_t id() const { return id_; }
 
@@ -158,7 +160,8 @@
   void InitClient(ClientType client_type,
                   scoped_ptr<FrameUserDataAndBinding> data_and_binding,
                   mojo::ViewTreeClientPtr view_tree_client,
-                  mojo::InterfaceRequest<mojom::Frame> frame_request);
+                  mojo::InterfaceRequest<mojom::Frame> frame_request,
+                  base::TimeTicks navigation_start_time);
 
   // Callback from OnConnect(). This does nothing (other than destroying
   // |data_and_binding|). See InitClient() for details as to why destruction of
@@ -173,16 +176,18 @@
   void OnWillNavigateAck(mojom::FrameClient* frame_client,
                          scoped_ptr<FrameUserData> user_data,
                          mojo::ViewTreeClientPtr view_tree_client,
-                         uint32 app_id);
+                         uint32 app_id,
+                         base::TimeTicks navigation_start_time);
 
   // Completes a navigation request; swapping the existing FrameClient to the
   // supplied arguments.
   void ChangeClient(mojom::FrameClient* frame_client,
                     scoped_ptr<FrameUserData> user_data,
                     mojo::ViewTreeClientPtr view_tree_client,
-                    uint32 app_id);
+                    uint32 app_id,
+                    base::TimeTicks navigation_start_time);
 
-  void SetView(mus::View* view);
+  void SetView(mus::Window* view);
 
   // Adds this to |frames| and recurses through the children calling the
   // same function.
@@ -196,6 +201,7 @@
   // no View the navigation waits until the View is available.
   void StartNavigate(mojo::URLRequestPtr request);
   void OnCanNavigateFrame(const GURL& url,
+                          base::TimeTicks navigation_start_time,
                           uint32_t app_id,
                           mojom::FrameClient* frame_client,
                           scoped_ptr<FrameUserData> user_data,
@@ -214,10 +220,10 @@
   void NotifyFrameLoadingStateChanged(const Frame* frame, bool loading);
   void NotifyDispatchFrameLoadEvent(const Frame* frame);
 
-  // mus::ViewObserver:
+  // mus::WindowObserver:
   void OnTreeChanged(const TreeChangeParams& params) override;
-  void OnViewDestroying(mus::View* view) override;
-  void OnViewEmbeddedAppDisconnected(mus::View* view) override;
+  void OnWindowDestroying(mus::Window* view) override;
+  void OnWindowEmbeddedAppDisconnected(mus::Window* view) override;
 
   // mojom::Frame:
   void PostMessageEventToFrame(uint32_t target_frame_id,
@@ -245,7 +251,7 @@
 
   FrameTree* const tree_;
   // WARNING: this may be null. See class description for details.
-  mus::View* view_;
+  mus::Window* view_;
   // The connection id returned from ViewManager::Embed(). Frames created by
   // way of OnCreatedFrame() inherit the id from the parent.
   mus::ConnectionSpecificId embedded_connection_id_;
diff --git a/components/web_view/frame_apptest.cc b/components/web_view/frame_apptest.cc
index 603b0b6..a8f0bb8c 100644
--- a/components/web_view/frame_apptest.cc
+++ b/components/web_view/frame_apptest.cc
@@ -10,10 +10,11 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/test_timeouts.h"
-#include "components/mus/public/cpp/view_observer.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
-#include "components/mus/public/cpp/view_tree_host_factory.h"
+#include "base/time/time.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
+#include "components/mus/public/cpp/window_tree_host_factory.h"
 #include "components/web_view/frame.h"
 #include "components/web_view/frame_connection.h"
 #include "components/web_view/frame_tree.h"
@@ -26,8 +27,8 @@
 #include "mojo/application/public/cpp/application_test_base.h"
 #include "mojo/application/public/cpp/service_provider_impl.h"
 
-using mus::View;
-using mus::ViewTreeConnection;
+using mus::Window;
+using mus::WindowTreeConnection;
 
 namespace web_view {
 
@@ -124,12 +125,17 @@
     return last_dispatch_load_event_frame_id_;
   }
 
+  base::TimeTicks last_navigation_start_time() const {
+    return last_navigation_start_time_;
+  }
+
   // mojom::FrameClient:
   void OnConnect(mojom::FramePtr frame,
                  uint32_t change_id,
-                 uint32_t view_id,
+                 uint32_t window_id,
                  mojom::ViewConnectType view_connect_type,
                  mojo::Array<mojom::FrameDataPtr> frames,
+                 int64_t navigation_start_time_ticks,
                  const OnConnectCallback& callback) override {
     connect_count_++;
     connect_frames_ = frames.Pass();
@@ -138,6 +144,9 @@
     callback.Run();
     if (!on_connect_callback_.is_null())
       on_connect_callback_.Run();
+
+    last_navigation_start_time_ =
+        base::TimeTicks::FromInternalValue(navigation_start_time_ticks);
   }
   void OnFrameAdded(uint32_t change_id, mojom::FrameDataPtr frame) override {
     adds_.push_back(frame.Pass());
@@ -196,6 +205,7 @@
   base::Closure on_dispatch_load_event_callback_;
   LoadingStateChangedNotification last_loading_state_changed_notification_;
   uint32_t last_dispatch_load_event_frame_id_;
+  base::TimeTicks last_navigation_start_time_;
 
   DISALLOW_COPY_AND_ASSIGN(TestFrameClient);
 };
@@ -206,7 +216,7 @@
 // a single FrameClient. In other words this maintains the data structures
 // needed to represent a client side frame. To obtain one use
 // FrameTest::WaitForViewAndFrame().
-class ViewAndFrame : public mus::ViewTreeDelegate {
+class ViewAndFrame : public mus::WindowTreeDelegate {
  public:
   ~ViewAndFrame() override {
     if (view_)
@@ -214,7 +224,7 @@
   }
 
   // The View associated with the frame.
-  mus::View* view() { return view_; }
+  mus::Window* view() { return view_; }
   TestFrameClient* test_frame_client() { return &test_frame_tree_client_; }
   mojom::Frame* server_frame() {
     return test_frame_tree_client_.server_frame();
@@ -226,7 +236,7 @@
   ViewAndFrame()
       : view_(nullptr), frame_client_binding_(&test_frame_tree_client_) {}
 
-  void set_view(View* view) { view_ = view; }
+  void set_view(Window* view) { view_ = view; }
 
   // Runs a message loop until the view and frame data have been received.
   void WaitForViewAndFrame() { run_loop_.Run(); }
@@ -255,16 +265,16 @@
       run_loop_.Quit();
   }
 
-  // Overridden from ViewTreeDelegate:
-  void OnEmbed(View* root) override {
+  // Overridden from WindowTreeDelegate:
+  void OnEmbed(Window* root) override {
     view_ = root;
     QuitRunLoopIfNecessary();
   }
-  void OnConnectionLost(ViewTreeConnection* connection) override {
+  void OnConnectionLost(WindowTreeConnection* connection) override {
     view_ = nullptr;
   }
 
-  mus::View* view_;
+  mus::Window* view_;
   base::RunLoop run_loop_;
   TestFrameClient test_frame_tree_client_;
   mojo::Binding<mojom::FrameClient> frame_client_binding_;
@@ -274,36 +284,44 @@
 
 class FrameTest : public mojo::test::ApplicationTestBase,
                   public mojo::ApplicationDelegate,
-                  public mus::ViewTreeDelegate,
+                  public mus::WindowTreeDelegate,
                   public mojo::InterfaceFactory<mojo::ViewTreeClient>,
                   public mojo::InterfaceFactory<mojom::FrameClient> {
  public:
   FrameTest() : most_recent_connection_(nullptr), window_manager_(nullptr) {}
 
-  ViewTreeConnection* most_recent_connection() {
+  WindowTreeConnection* most_recent_connection() {
     return most_recent_connection_;
   }
 
  protected:
-  ViewTreeConnection* window_manager() { return window_manager_; }
+  WindowTreeConnection* window_manager() { return window_manager_; }
   TestFrameTreeDelegate* frame_tree_delegate() {
     return frame_tree_delegate_.get();
   }
   FrameTree* frame_tree() { return frame_tree_.get(); }
   ViewAndFrame* root_view_and_frame() { return root_view_and_frame_.get(); }
 
-  scoped_ptr<ViewAndFrame> NavigateFrame(ViewAndFrame* view_and_frame) {
+  scoped_ptr<ViewAndFrame> NavigateFrameWithStartTime(
+      ViewAndFrame* view_and_frame,
+      base::TimeTicks navigation_start_time) {
     mojo::URLRequestPtr request(mojo::URLRequest::New());
     request->url = mojo::String::From(application_impl()->url());
+    request->originating_time_ticks = navigation_start_time.ToInternalValue();
     view_and_frame->server_frame()->RequestNavigate(
         mojom::NAVIGATION_TARGET_TYPE_EXISTING_FRAME,
         view_and_frame->view()->id(), request.Pass());
     return WaitForViewAndFrame();
   }
 
+  scoped_ptr<ViewAndFrame> NavigateFrame(ViewAndFrame* view_and_frame) {
+    return NavigateFrameWithStartTime(view_and_frame, base::TimeTicks());
+  }
+
   // Creates a new shared frame as a child of |parent|.
   scoped_ptr<ViewAndFrame> CreateChildViewAndFrame(ViewAndFrame* parent) {
-    mus::View* child_frame_view = parent->view()->connection()->CreateView();
+    mus::Window* child_frame_view =
+        parent->view()->connection()->CreateWindow();
     parent->view()->AddChild(child_frame_view);
 
     scoped_ptr<ViewAndFrame> view_and_frame(new ViewAndFrame);
@@ -340,18 +358,18 @@
     return true;
   }
 
-  // Overridden from ViewTreeDelegate:
-  void OnEmbed(View* root) override {
+  // Overridden from WindowTreeDelegate:
+  void OnEmbed(Window* root) override {
     most_recent_connection_ = root->connection();
     QuitRunLoop();
   }
-  void OnConnectionLost(ViewTreeConnection* connection) override {}
+  void OnConnectionLost(WindowTreeConnection* connection) override {}
 
   // Overridden from testing::Test:
   void SetUp() override {
     ApplicationTestBase::SetUp();
 
-    mus::CreateSingleViewTreeHost(application_impl(), this, &host_);
+    mus::CreateSingleWindowTreeHost(application_impl(), this, &host_);
 
     ASSERT_TRUE(DoRunLoopWithTimeout());
     std::swap(window_manager_, most_recent_connection_);
@@ -364,12 +382,12 @@
     mojom::FrameClient* frame_client = frame_connection->frame_client();
     mojo::ViewTreeClientPtr view_tree_client =
         frame_connection->GetViewTreeClient();
-    mus::View* frame_root_view = window_manager()->CreateView();
+    mus::Window* frame_root_view = window_manager()->CreateWindow();
     window_manager()->GetRoot()->AddChild(frame_root_view);
-    frame_tree_.reset(
-        new FrameTree(0u, frame_root_view, view_tree_client.Pass(),
-                      frame_tree_delegate_.get(), frame_client,
-                      frame_connection.Pass(), Frame::ClientPropertyMap()));
+    frame_tree_.reset(new FrameTree(
+        0u, frame_root_view, view_tree_client.Pass(),
+        frame_tree_delegate_.get(), frame_client, frame_connection.Pass(),
+        Frame::ClientPropertyMap(), base::TimeTicks::Now()));
     root_view_and_frame_ = WaitForViewAndFrame();
   }
 
@@ -386,13 +404,13 @@
       mojo::ApplicationConnection* connection,
       mojo::InterfaceRequest<mojo::ViewTreeClient> request) override {
     if (view_and_frame_) {
-      mus::ViewTreeConnection::Create(
+      mus::WindowTreeConnection::Create(
           view_and_frame_.get(), request.Pass(),
-          mus::ViewTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
+          mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
     } else {
-      mus::ViewTreeConnection::Create(
+      mus::WindowTreeConnection::Create(
           this, request.Pass(),
-          mus::ViewTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
+          mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
     }
   }
 
@@ -410,10 +428,10 @@
   mojo::ViewTreeHostPtr host_;
 
   // Used to receive the most recent view manager loaded by an embed action.
-  ViewTreeConnection* most_recent_connection_;
+  WindowTreeConnection* most_recent_connection_;
   // The View Manager connection held by the window manager (app running at the
   // root view).
-  ViewTreeConnection* window_manager_;
+  WindowTreeConnection* window_manager_;
 
   scoped_ptr<ViewAndFrame> view_and_frame_;
 
@@ -461,7 +479,7 @@
   scoped_ptr<ViewAndFrame> navigated_child_view_and_frame =
       NavigateFrame(child_view_and_frame.get()).Pass();
 
-  // Delete the ViewTreeConnection for the child, which should trigger
+  // Delete the WindowTreeConnection for the child, which should trigger
   // notification.
   delete navigated_child_view_and_frame->view()->connection();
   ASSERT_EQ(1u, frame_tree()->root()->children().size());
@@ -535,4 +553,20 @@
                           ->last_dispatch_load_event_frame_id();
   EXPECT_EQ(child_frame_id, frame_id);
 }
+
+TEST_F(FrameTest, PassAlongNavigationStartTime) {
+  scoped_ptr<ViewAndFrame> child_view_and_frame(
+      CreateChildViewAndFrame(root_view_and_frame()));
+  ASSERT_TRUE(child_view_and_frame);
+
+  base::TimeTicks navigation_start_time = base::TimeTicks::FromInternalValue(1);
+  scoped_ptr<ViewAndFrame> navigated_child_view_and_frame =
+      NavigateFrameWithStartTime(child_view_and_frame.get(),
+                                 navigation_start_time)
+          .Pass();
+  EXPECT_EQ(navigation_start_time,
+            navigated_child_view_and_frame->test_frame_client()
+                ->last_navigation_start_time());
+}
+
 }  // namespace web_view
diff --git a/components/web_view/frame_tree.cc b/components/web_view/frame_tree.cc
index e8d071f..7132739 100644
--- a/components/web_view/frame_tree.cc
+++ b/components/web_view/frame_tree.cc
@@ -10,12 +10,13 @@
 namespace web_view {
 
 FrameTree::FrameTree(uint32_t root_app_id,
-                     mus::View* view,
+                     mus::Window* view,
                      mojo::ViewTreeClientPtr view_tree_client,
                      FrameTreeDelegate* delegate,
                      mojom::FrameClient* root_client,
                      scoped_ptr<FrameUserData> user_data,
-                     const Frame::ClientPropertyMap& client_properties)
+                     const Frame::ClientPropertyMap& client_properties,
+                     base::TimeTicks navigation_start_time)
     : view_(view),
       delegate_(delegate),
       root_(new Frame(this,
@@ -28,7 +29,7 @@
                       client_properties)),
       progress_(0.f),
       change_id_(1u) {
-  root_->Init(nullptr, view_tree_client.Pass(), nullptr);
+  root_->Init(nullptr, view_tree_client.Pass(), nullptr, navigation_start_time);
 }
 
 FrameTree::~FrameTree() {
@@ -48,13 +49,13 @@
   mojom::FrameClient* raw_client = client.get();
   scoped_ptr<FrameUserData> user_data =
       delegate_->CreateUserDataForNewFrame(client.Pass());
-  mus::View* frame_view = root_->view()->GetChildById(frame_id);
+  mus::Window* frame_view = root_->view()->GetChildById(frame_id);
   // |frame_view| may be null if the View hasn't been created yet. If this is
   // the case the View will be connected to the Frame in Frame::OnTreeChanged.
   Frame* frame =
       new Frame(this, frame_view, frame_id, app_id, ViewOwnership::OWNS_VIEW,
                 raw_client, user_data.Pass(), client_properties);
-  frame->Init(parent, nullptr, frame_request.Pass());
+  frame->Init(parent, nullptr, frame_request.Pass(), base::TimeTicks());
   return frame;
 }
 
diff --git a/components/web_view/frame_tree.h b/components/web_view/frame_tree.h
index aadcdba..f252ceb 100644
--- a/components/web_view/frame_tree.h
+++ b/components/web_view/frame_tree.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_WEB_VIEW_FRAME_TREE_H_
 #define COMPONENTS_WEB_VIEW_FRAME_TREE_H_
 
+#include "base/time/time.h"
 #include "components/mus/public/interfaces/view_tree.mojom.h"
 #include "components/web_view/frame.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/array.h"
@@ -36,12 +37,13 @@
   // |root_app_id| is a unique identifier of the app providing |root_client|.
   // See Frame for details on app id's.
   FrameTree(uint32_t root_app_id,
-            mus::View* view,
+            mus::Window* view,
             mojo::ViewTreeClientPtr view_tree_client,
             FrameTreeDelegate* delegate,
             mojom::FrameClient* root_client,
             scoped_ptr<FrameUserData> user_data,
-            const Frame::ClientPropertyMap& client_properties);
+            const Frame::ClientPropertyMap& client_properties,
+            base::TimeTicks navigation_start_time);
   ~FrameTree();
 
   const Frame* root() const { return root_; }
@@ -72,7 +74,7 @@
                              const mojo::String& name,
                              const mojo::Array<uint8_t>& value);
 
-  mus::View* view_;
+  mus::Window* view_;
 
   FrameTreeDelegate* delegate_;
 
diff --git a/components/web_view/frame_tree_delegate.cc b/components/web_view/frame_tree_delegate.cc
index c04ec70..dbc3773 100644
--- a/components/web_view/frame_tree_delegate.cc
+++ b/components/web_view/frame_tree_delegate.cc
@@ -8,7 +8,7 @@
 
 void FrameTreeDelegate::DidCreateFrame(Frame* frame) {}
 void FrameTreeDelegate::DidDestroyFrame(Frame* frame) {}
-void FrameTreeDelegate::OnViewEmbeddedInFrameDisconnected(Frame* frame) {}
+void FrameTreeDelegate::OnWindowEmbeddedInFrameDisconnected(Frame* frame) {}
 void FrameTreeDelegate::OnFindInFrameCountUpdated(int32_t request_id,
                                                   Frame* frame,
                                                   int32_t count,
diff --git a/components/web_view/frame_tree_delegate.h b/components/web_view/frame_tree_delegate.h
index 4b317a79..55be5612 100644
--- a/components/web_view/frame_tree_delegate.h
+++ b/components/web_view/frame_tree_delegate.h
@@ -86,7 +86,7 @@
   // . The app is still alive, but is shutting down.
   // Frame does nothing in response to this, but the delegate may wish to take
   // action.
-  virtual void OnViewEmbeddedInFrameDisconnected(Frame* frame);
+  virtual void OnWindowEmbeddedInFrameDisconnected(Frame* frame);
 
   // Reports the current find state back to our owner.
   virtual void OnFindInFrameCountUpdated(int32_t request_id,
diff --git a/components/web_view/navigation_controller.cc b/components/web_view/navigation_controller.cc
index ef6010b..87304fa 100644
--- a/components/web_view/navigation_controller.cc
+++ b/components/web_view/navigation_controller.cc
@@ -75,7 +75,7 @@
 
   pending_entry_index_ = current_index - 1;
   // TODO(erg): Transition type handled here.
-  NavigateToPendingEntry(ReloadType::NO_RELOAD);
+  NavigateToPendingEntry(ReloadType::NO_RELOAD, true);
 }
 
 void NavigationController::GoForward() {
@@ -93,17 +93,19 @@
 
   pending_entry_index_ = current_index + 1;
   // TODO(erg): Transition type handled here.
-  NavigateToPendingEntry(ReloadType::NO_RELOAD);
+  NavigateToPendingEntry(ReloadType::NO_RELOAD, true);
 }
 
 void NavigationController::LoadURL(mojo::URLRequestPtr request) {
   // TODO(erg): This mimics part of NavigationControllerImpl::LoadURL(), minus
   // all the error checking.
   SetPendingEntry(make_scoped_ptr(new NavigationEntry(request.Pass())));
-  NavigateToPendingEntry(ReloadType::NO_RELOAD);
+  NavigateToPendingEntry(ReloadType::NO_RELOAD, false);
 }
 
-void NavigationController::NavigateToPendingEntry(ReloadType reload_type) {
+void NavigationController::NavigateToPendingEntry(
+    ReloadType reload_type,
+    bool update_navigation_start_time) {
   // TODO(erg): Deal with session history navigations while trying to navigate
   // to a slow-to-commit page.
 
@@ -117,7 +119,8 @@
 
   // TODO(erg): Eventually, we need to deal with restoring the state of the
   // full tree. For now, we'll just shell back to the WebView.
-  delegate_->OnNavigate(pending_entry_->BuildURLRequest());
+  delegate_->OnNavigate(
+      pending_entry_->BuildURLRequest(update_navigation_start_time));
 }
 
 void NavigationController::DiscardPendingEntry(bool was_failure) {
diff --git a/components/web_view/navigation_controller.h b/components/web_view/navigation_controller.h
index 1d4a0ae..635dfe5 100644
--- a/components/web_view/navigation_controller.h
+++ b/components/web_view/navigation_controller.h
@@ -41,7 +41,8 @@
 
   void LoadURL(mojo::URLRequestPtr request);
 
-  void NavigateToPendingEntry(ReloadType reload_type);
+  void NavigateToPendingEntry(ReloadType reload_type,
+                              bool update_navigation_start_time);
 
   // Takes ownership of a pending entry, and adds it to the current list.
   //
diff --git a/components/web_view/navigation_entry.cc b/components/web_view/navigation_entry.cc
index 0b3aaa8..24d6db92 100644
--- a/components/web_view/navigation_entry.cc
+++ b/components/web_view/navigation_entry.cc
@@ -7,14 +7,20 @@
 namespace web_view {
 
 NavigationEntry::NavigationEntry(mojo::URLRequestPtr original_request)
-    : url_request_(original_request.Pass()) {}
+    : url_request_(original_request.Pass()) {
+  if (url_request_.originating_time().is_null())
+    url_request_.set_originating_time(base::TimeTicks::Now());
+}
 
 NavigationEntry::NavigationEntry(const GURL& raw_url)
     : url_request_(raw_url) {}
 
 NavigationEntry::~NavigationEntry() {}
 
-mojo::URLRequestPtr NavigationEntry::BuildURLRequest() const {
+mojo::URLRequestPtr NavigationEntry::BuildURLRequest(
+    bool update_originating_time) {
+  if (update_originating_time)
+    url_request_.set_originating_time(base::TimeTicks::Now());
   return url_request_.Clone();
 }
 
diff --git a/components/web_view/navigation_entry.h b/components/web_view/navigation_entry.h
index db3df6a..2e5f6a1 100644
--- a/components/web_view/navigation_entry.h
+++ b/components/web_view/navigation_entry.h
@@ -21,7 +21,7 @@
 
   // Builds a copy of the URLRequest that generated this navigation. This
   // method is heavyweight as it clones a few mojo pipes.
-  mojo::URLRequestPtr BuildURLRequest() const;
+  mojo::URLRequestPtr BuildURLRequest(bool update_originating_time);
 
  private:
   // TODO(erg): This is not enough information to regenerate the state of the
diff --git a/components/web_view/pending_web_view_load.cc b/components/web_view/pending_web_view_load.cc
index 54fa39b54..fcb40db 100644
--- a/components/web_view/pending_web_view_load.cc
+++ b/components/web_view/pending_web_view_load.cc
@@ -19,6 +19,8 @@
 void PendingWebViewLoad::Init(mojo::URLRequestPtr request) {
   DCHECK(!frame_connection_);
   pending_url_ = GURL(request->url);
+  navigation_start_time_ =
+      base::TimeTicks::FromInternalValue(request->originating_time_ticks);
   frame_connection_.reset(new FrameConnection);
   frame_connection_->Init(web_view_->app_, request.Pass(),
                           base::Bind(&PendingWebViewLoad::OnGotContentHandlerID,
diff --git a/components/web_view/pending_web_view_load.h b/components/web_view/pending_web_view_load.h
index b2a11217..b7070bd 100644
--- a/components/web_view/pending_web_view_load.h
+++ b/components/web_view/pending_web_view_load.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
 #include "mojo/services/network/public/interfaces/url_loader.mojom.h"
 #include "url/gurl.h"
 
@@ -35,6 +36,10 @@
 
   const GURL& pending_url() const { return pending_url_; }
 
+  base::TimeTicks navigation_start_time() const {
+    return navigation_start_time_;
+  }
+
  private:
   void OnGotContentHandlerID();
 
@@ -45,6 +50,8 @@
 
   scoped_ptr<FrameConnection> frame_connection_;
 
+  base::TimeTicks navigation_start_time_;
+
   DISALLOW_COPY_AND_ASSIGN(PendingWebViewLoad);
 };
 
diff --git a/components/web_view/public/cpp/web_view.cc b/components/web_view/public/cpp/web_view.cc
index d2ae310..51fd1d6 100644
--- a/components/web_view/public/cpp/web_view.cc
+++ b/components/web_view/public/cpp/web_view.cc
@@ -5,7 +5,7 @@
 #include "components/web_view/public/cpp/web_view.h"
 
 #include "base/bind.h"
-#include "components/mus/public/cpp/view.h"
+#include "components/mus/public/cpp/window.h"
 #include "mojo/application/public/cpp/application_impl.h"
 
 namespace web_view {
@@ -20,7 +20,7 @@
 WebView::WebView(mojom::WebViewClient* client) : binding_(client) {}
 WebView::~WebView() {}
 
-void WebView::Init(mojo::ApplicationImpl* app, mus::View* view) {
+void WebView::Init(mojo::ApplicationImpl* app, mus::Window* window) {
   mojo::URLRequestPtr request(mojo::URLRequest::New());
   request->url = "mojo:web_view";
 
@@ -35,8 +35,8 @@
 
   mojo::ViewTreeClientPtr view_tree_client;
   web_view_->GetViewTreeClient(GetProxy(&view_tree_client));
-  view->Embed(view_tree_client.Pass(), mojo::ViewTree::ACCESS_POLICY_EMBED_ROOT,
-              base::Bind(&OnEmbed));
+  window->Embed(view_tree_client.Pass(),
+                mojo::ViewTree::ACCESS_POLICY_EMBED_ROOT, base::Bind(&OnEmbed));
 }
 
 }  // namespace web_view
diff --git a/components/web_view/public/cpp/web_view.h b/components/web_view/public/cpp/web_view.h
index b10c0d3..0eae5ede 100644
--- a/components/web_view/public/cpp/web_view.h
+++ b/components/web_view/public/cpp/web_view.h
@@ -15,7 +15,7 @@
 }
 
 namespace mus {
-class View;
+class Window;
 }
 
 namespace web_view {
@@ -25,7 +25,7 @@
   explicit WebView(mojom::WebViewClient* client);
   ~WebView();
 
-  void Init(mojo::ApplicationImpl* app, mus::View* view);
+  void Init(mojo::ApplicationImpl* app, mus::Window* window);
 
   mojom::WebView* web_view() { return web_view_.get(); }
 
diff --git a/components/web_view/public/interfaces/frame.mojom b/components/web_view/public/interfaces/frame.mojom
index 2808cfde..4290882 100644
--- a/components/web_view/public/interfaces/frame.mojom
+++ b/components/web_view/public/interfaces/frame.mojom
@@ -143,12 +143,15 @@
   // Called once per client. |frame_data| gives the contents of the tree.
   // |view_id| is the id of the view the FrameClient should render to. If a
   // ViewTreeClient is asked for then |view_id| is the same id as that of the
-  // View supplied to ViewTreeClient::OnEmbed().
+  // View supplied to ViewTreeClient::OnEmbed(). |navigation_start_time_ticks|
+  // is the time when the navigation resulting in this OnConnect() call was
+  // started.
   OnConnect(Frame? frame,
             uint32 change_id,
             uint32 view_id,
             ViewConnectType view_connect_type,
-            array<FrameData>? frame_data) => ();
+            array<FrameData>? frame_data,
+            int64 navigation_start_time_ticks) => ();
 
   // Called when a new frame is added to the tree.
   OnFrameAdded(uint32 change_id, FrameData frame_data);
diff --git a/components/web_view/test_frame_tree_delegate.cc b/components/web_view/test_frame_tree_delegate.cc
index 2b7ee8cc..8c439b2 100644
--- a/components/web_view/test_frame_tree_delegate.cc
+++ b/components/web_view/test_frame_tree_delegate.cc
@@ -98,7 +98,7 @@
   }
 }
 
-void TestFrameTreeDelegate::OnViewEmbeddedInFrameDisconnected(Frame* frame) {
+void TestFrameTreeDelegate::OnWindowEmbeddedInFrameDisconnected(Frame* frame) {
   if (waiting_for_frame_disconnected_ == frame) {
     waiting_for_frame_disconnected_ = nullptr;
     run_loop_->Quit();
diff --git a/components/web_view/test_frame_tree_delegate.h b/components/web_view/test_frame_tree_delegate.h
index 1f021ee..21cb581 100644
--- a/components/web_view/test_frame_tree_delegate.h
+++ b/components/web_view/test_frame_tree_delegate.h
@@ -33,7 +33,7 @@
   // Waits for DidDestroyFrame() to be called with |frame|.
   void WaitForDestroyFrame(Frame* frame);
 
-  // Waits for OnViewEmbeddedInFrameDisconnected() to be called with |frame|.
+  // Waits for OnWindowEmbeddedInFrameDisconnected() to be called with |frame|.
   void WaitForFrameDisconnected(Frame* frame);
 
   // TestFrameTreeDelegate:
@@ -53,7 +53,7 @@
   void DidNavigateLocally(Frame* source, const GURL& url) override;
   void DidCreateFrame(Frame* frame) override;
   void DidDestroyFrame(Frame* frame) override;
-  void OnViewEmbeddedInFrameDisconnected(Frame* frame) override;
+  void OnWindowEmbeddedInFrameDisconnected(Frame* frame) override;
 
  private:
   bool is_waiting() const { return run_loop_.get(); }
diff --git a/components/web_view/test_runner/test_runner_application_delegate.cc b/components/web_view/test_runner/test_runner_application_delegate.cc
index 24d2c517..76e5bc4d 100644
--- a/components/web_view/test_runner/test_runner_application_delegate.cc
+++ b/components/web_view/test_runner/test_runner_application_delegate.cc
@@ -15,10 +15,10 @@
 #include "base/path_service.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_restrictions.h"
-#include "components/mus/public/cpp/scoped_view_ptr.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
-#include "components/mus/public/cpp/view_tree_host_factory.h"
+#include "components/mus/public/cpp/scoped_window_ptr.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_host_factory.h"
 #include "components/test_runner/blink_test_platform_support.h"
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/application/public/cpp/application_impl.h"
@@ -40,7 +40,7 @@
 
 TestRunnerApplicationDelegate::~TestRunnerApplicationDelegate() {
   if (root_)
-    mus::ScopedViewPtr::DeleteViewOrViewManager(root_);
+    mus::ScopedWindowPtr::DeleteWindowOrWindowManager(root_);
 }
 
 void TestRunnerApplicationDelegate::LaunchURL(const GURL& test_url) {
@@ -55,7 +55,7 @@
 
 void TestRunnerApplicationDelegate::Terminate() {
   if (root_)
-    mus::ScopedViewPtr::DeleteViewOrViewManager(root_);
+    mus::ScopedWindowPtr::DeleteWindowOrWindowManager(root_);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -66,7 +66,7 @@
     NOTREACHED() << "Test environment could not be properly set up for blink.";
   }
   app_ = app;
-  mus::CreateSingleViewTreeHost(app_, this, &host_);
+  mus::CreateSingleWindowTreeHost(app_, this, &host_);
 }
 
 bool TestRunnerApplicationDelegate::ConfigureIncomingConnection(
@@ -78,7 +78,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // mus::ViewTreeDelegate implementation:
 
-void TestRunnerApplicationDelegate::OnEmbed(mus::View* root) {
+void TestRunnerApplicationDelegate::OnEmbed(mus::Window* root) {
   root_ = root;
 
   // If this is a sys-check, then terminate in the next cycle.
@@ -94,7 +94,7 @@
   const gfx::Size kViewportSize(800, 600);
   host_->SetSize(mojo::Size::From(kViewportSize));
 
-  content_ = root_->connection()->CreateView();
+  content_ = root_->connection()->CreateWindow();
   root_->AddChild(content_);
   content_->SetBounds(*mojo::Rect::From(gfx::Rect(kViewportSize)));
   content_->SetVisible(true);
@@ -111,7 +111,7 @@
 }
 
 void TestRunnerApplicationDelegate::OnConnectionLost(
-    mus::ViewTreeConnection* connection) {
+    mus::WindowTreeConnection* connection) {
   root_ = nullptr;
   app_->Quit();
 }
diff --git a/components/web_view/test_runner/test_runner_application_delegate.h b/components/web_view/test_runner/test_runner_application_delegate.h
index 03d5b5e..6299580 100644
--- a/components/web_view/test_runner/test_runner_application_delegate.h
+++ b/components/web_view/test_runner/test_runner_application_delegate.h
@@ -7,7 +7,7 @@
 
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
 #include "components/mus/public/interfaces/view_tree_host.mojom.h"
 #include "components/test_runner/test_info_extractor.h"
 #include "components/web_view/public/cpp/web_view.h"
@@ -27,7 +27,7 @@
 
 class TestRunnerApplicationDelegate
     : public mojo::ApplicationDelegate,
-      public mus::ViewTreeDelegate,
+      public mus::WindowTreeDelegate,
       public mojom::WebViewClient,
       public LayoutTestRunner,
       public mojo::InterfaceFactory<LayoutTestRunner> {
@@ -44,9 +44,9 @@
   bool ConfigureIncomingConnection(
       mojo::ApplicationConnection* connection) override;
 
-  // mus::ViewTreeDelegate:
-  void OnEmbed(mus::View* root) override;
-  void OnConnectionLost(mus::ViewTreeConnection* connection) override;
+  // mus::WindowTreeDelegate:
+  void OnEmbed(mus::Window* root) override;
+  void OnConnectionLost(mus::WindowTreeConnection* connection) override;
 
   // mojom::WebViewClient:
   void TopLevelNavigateRequest(mojo::URLRequestPtr request) override;
@@ -71,8 +71,8 @@
   mojo::ApplicationImpl* app_;
   mojo::ViewTreeHostPtr host_;
 
-  mus::View* root_;
-  mus::View* content_;
+  mus::Window* root_;
+  mus::Window* content_;
   scoped_ptr<WebView> web_view_;
 
   scoped_ptr<test_runner::TestInfoExtractor> test_extractor_;
diff --git a/components/web_view/url_request_cloneable.cc b/components/web_view/url_request_cloneable.cc
index 4ee870aa..db601a5 100644
--- a/components/web_view/url_request_cloneable.cc
+++ b/components/web_view/url_request_cloneable.cc
@@ -24,7 +24,9 @@
       auto_follow_redirects_(original_request->auto_follow_redirects),
       bypass_cache_(original_request->bypass_cache),
       original_body_null_(original_request->body.is_null()),
-      body_(original_request->body.size()) {
+      body_(original_request->body.size()),
+      originating_time_(base::TimeTicks::FromInternalValue(
+          original_request->originating_time_ticks)) {
   // TODO(erg): Maybe we can do some sort of async copy here?
   for (size_t i = 0; i < original_request->body.size(); ++i) {
     mojo::common::BlockingCopyToString(original_request->body[i].Pass(),
@@ -71,6 +73,8 @@
     }
   }
 
+  request->originating_time_ticks = originating_time_.ToInternalValue();
+
   return request.Pass();
 }
 
diff --git a/components/web_view/url_request_cloneable.h b/components/web_view/url_request_cloneable.h
index b8b3c3d0..18f3b3e9 100644
--- a/components/web_view/url_request_cloneable.h
+++ b/components/web_view/url_request_cloneable.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/basictypes.h"
+#include "base/time/time.h"
 #include "mojo/services/network/public/interfaces/url_loader.mojom.h"
 #include "url/gurl.h"
 
@@ -28,6 +29,11 @@
   // Creates a new URLRequest.
   mojo::URLRequestPtr Clone() const;
 
+  base::TimeTicks originating_time() const { return originating_time_; }
+  void set_originating_time(base::TimeTicks value) {
+    originating_time_ = value;
+  }
+
  private:
   // All of these are straight from mojo::URLRequest.
   mojo::String url_;
@@ -47,6 +53,8 @@
   // AsURLRequest() is called.
   std::vector<std::string> body_;
 
+  base::TimeTicks originating_time_;
+
   DISALLOW_COPY_AND_ASSIGN(URLRequestCloneable);
 };
 
diff --git a/components/web_view/web_view_apptest.cc b/components/web_view/web_view_apptest.cc
index 05faf55..63e42da 100644
--- a/components/web_view/web_view_apptest.cc
+++ b/components/web_view/web_view_apptest.cc
@@ -10,10 +10,10 @@
 #include "base/logging.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
-#include "components/mus/public/cpp/scoped_view_ptr.h"
-#include "components/mus/public/cpp/tests/view_manager_test_base.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
+#include "components/mus/public/cpp/scoped_window_ptr.h"
+#include "components/mus/public/cpp/tests/window_server_test_base.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
 #include "mojo/util/filename_util.h"
 #include "url/gurl.h"
 
@@ -40,7 +40,7 @@
 }
 }
 
-class WebViewTest : public mus::ViewManagerTestBase,
+class WebViewTest : public mus::WindowServerTestBase,
                     public mojom::WebViewClient {
  public:
   WebViewTest()
@@ -94,25 +94,26 @@
 
   // Overridden from ApplicationDelegate:
   void Initialize(mojo::ApplicationImpl* app) override {
-    ViewManagerTestBase::Initialize(app);
+    WindowServerTestBase::Initialize(app);
     app_ = app;
   }
 
   // Overridden from ViewTreeDelegate:
-  void OnEmbed(mus::View* root) override {
-    content_ = root->connection()->CreateView();
+  void OnEmbed(mus::Window* root) override {
+    content_ = root->connection()->CreateWindow();
     content_->SetBounds(root->bounds());
     root->AddChild(content_);
     content_->SetVisible(true);
 
     web_view_.Init(app_, content_);
 
-    ViewManagerTestBase::OnEmbed(root);
+    WindowServerTestBase::OnEmbed(root);
   }
 
   void TearDown() override {
-    mus::ScopedViewPtr::DeleteViewOrViewManager(window_manager()->GetRoot());
-    ViewManagerTestBase::TearDown();
+    mus::ScopedWindowPtr::DeleteWindowOrWindowManager(
+        window_manager()->GetRoot());
+    WindowServerTestBase::TearDown();
   }
 
   // Overridden from web_view::mojom::WebViewClient:
@@ -148,7 +149,7 @@
 
   mojo::ApplicationImpl* app_;
 
-  mus::View* content_;
+  mus::Window* content_;
 
   web_view::WebView web_view_;
 
diff --git a/components/web_view/web_view_impl.cc b/components/web_view/web_view_impl.cc
index 3320733..b590e0f 100644
--- a/components/web_view/web_view_impl.cc
+++ b/components/web_view/web_view_impl.cc
@@ -9,9 +9,9 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "components/devtools_service/public/cpp/switches.h"
-#include "components/mus/public/cpp/scoped_view_ptr.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
+#include "components/mus/public/cpp/scoped_window_ptr.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/web_view/client_initiated_frame_connection.h"
 #include "components/web_view/frame.h"
 #include "components/web_view/frame_connection.h"
@@ -59,7 +59,7 @@
     content_->RemoveObserver(this);
   if (root_) {
     root_->RemoveObserver(this);
-    mus::ScopedViewPtr::DeleteViewOrViewManager(root_);
+    mus::ScopedWindowPtr::DeleteWindowOrWindowManager(root_);
   }
 }
 
@@ -74,7 +74,7 @@
 
   client_->TopLevelNavigationStarted(pending_url.spec());
 
-  content_ = root_->connection()->CreateView();
+  content_ = root_->connection()->CreateWindow();
   content_->SetBounds(*mojo::Rect::From(
       gfx::Rect(0, 0, root_->bounds().width, root_->bounds().height)));
   root_->AddChild(content_);
@@ -99,7 +99,8 @@
   const uint32_t content_handler_id = frame_connection->GetContentHandlerID();
   frame_tree_.reset(new FrameTree(content_handler_id, content_,
                                   view_tree_client.Pass(), this, frame_client,
-                                  frame_connection.Pass(), client_properties));
+                                  frame_connection.Pass(), client_properties,
+                                  pending_load->navigation_start_time()));
 }
 
 void WebViewImpl::PreOrderDepthFirstTraverseTree(Frame* node,
@@ -118,9 +119,9 @@
 
 void WebViewImpl::GetViewTreeClient(
     mojo::InterfaceRequest<mojo::ViewTreeClient> view_tree_client) {
-  mus::ViewTreeConnection::Create(
+  mus::WindowTreeConnection::Create(
       this, view_tree_client.Pass(),
-      mus::ViewTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
+      mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
 }
 
 void WebViewImpl::Find(const mojo::String& search_text,
@@ -145,9 +146,9 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// WebViewImpl, mus::ViewTreeDelegate implementation:
+// WebViewImpl, mus::WindowTreeDelegate implementation:
 
-void WebViewImpl::OnEmbed(mus::View* root) {
+void WebViewImpl::OnEmbed(mus::Window* root) {
   // We must have been granted embed root priviledges, otherwise we can't
   // Embed() in any descendants.
   DCHECK(root->connection()->IsEmbedRoot());
@@ -158,16 +159,16 @@
     OnLoad(pending_load_->pending_url());
 }
 
-void WebViewImpl::OnConnectionLost(mus::ViewTreeConnection* connection) {
+void WebViewImpl::OnConnectionLost(mus::WindowTreeConnection* connection) {
   root_ = nullptr;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // WebViewImpl, mus::ViewObserver implementation:
 
-void WebViewImpl::OnViewBoundsChanged(mus::View* view,
-                                      const mojo::Rect& old_bounds,
-                                      const mojo::Rect& new_bounds) {
+void WebViewImpl::OnWindowBoundsChanged(mus::Window* view,
+                                        const mojo::Rect& old_bounds,
+                                        const mojo::Rect& new_bounds) {
   if (view != content_) {
     mojo::Rect rect;
     rect.width = new_bounds.width;
@@ -177,7 +178,7 @@
   }
 }
 
-void WebViewImpl::OnViewDestroyed(mus::View* view) {
+void WebViewImpl::OnWindowDestroyed(mus::Window* view) {
   // |FrameTree| cannot outlive the content view.
   if (view == content_) {
     frame_tree_.reset();
diff --git a/components/web_view/web_view_impl.h b/components/web_view/web_view_impl.h
index 534c5aa2..1e2125e 100644
--- a/components/web_view/web_view_impl.h
+++ b/components/web_view/web_view_impl.h
@@ -10,8 +10,8 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
-#include "components/mus/public/cpp/view_observer.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
 #include "components/web_view/find_controller.h"
 #include "components/web_view/find_controller_delegate.h"
 #include "components/web_view/frame_devtools_agent_delegate.h"
@@ -39,8 +39,8 @@
 }
 
 class WebViewImpl : public mojom::WebView,
-                    public mus::ViewTreeDelegate,
-                    public mus::ViewObserver,
+                    public mus::WindowTreeDelegate,
+                    public mus::WindowObserver,
                     public FrameTreeDelegate,
                     public FrameDevToolsAgentDelegate,
                     public NavigationControllerDelegate,
@@ -70,15 +70,15 @@
   void GoBack() override;
   void GoForward() override;
 
-  // Overridden from mus::ViewTreeDelegate:
-  void OnEmbed(mus::View* root) override;
-  void OnConnectionLost(mus::ViewTreeConnection* connection) override;
+  // Overridden from mus::WindowTreeDelegate:
+  void OnEmbed(mus::Window* root) override;
+  void OnConnectionLost(mus::WindowTreeConnection* connection) override;
 
-  // Overridden from mus::ViewObserver:
-  void OnViewBoundsChanged(mus::View* view,
-                           const mojo::Rect& old_bounds,
-                           const mojo::Rect& new_bounds) override;
-  void OnViewDestroyed(mus::View* view) override;
+  // Overridden from mus::WindowObserver:
+  void OnWindowBoundsChanged(mus::Window* view,
+                             const mojo::Rect& old_bounds,
+                             const mojo::Rect& new_bounds) override;
+  void OnWindowDestroyed(mus::Window* view) override;
 
   // Overridden from FrameTreeDelegate:
   scoped_ptr<FrameUserData> CreateUserDataForNewFrame(
@@ -118,8 +118,8 @@
   mojo::ApplicationImpl* app_;
   mojom::WebViewClientPtr client_;
   mojo::StrongBinding<WebView> binding_;
-  mus::View* root_;
-  mus::View* content_;
+  mus::Window* root_;
+  mus::Window* content_;
   scoped_ptr<FrameTree> frame_tree_;
 
   // When LoadRequest() is called a PendingWebViewLoad is created to wait for
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
index c0a64e0..a932c4d 100644
--- a/content/browser/accessibility/browser_accessibility_win.cc
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -269,7 +269,7 @@
 
   gfx::Point point(x_left, y_top);
   if (!GetGlobalBoundsRect().Contains(point)) {
-    // Return S_FALSE and VT_EMPTY when the outside the object's boundaries.
+    // Return S_FALSE and VT_EMPTY when outside the object's boundaries.
     child->vt = VT_EMPTY;
     return S_FALSE;
   }
@@ -2463,33 +2463,109 @@
 }
 
 //
-// IAccessibleHyperlink not implemented.
+// IAccessibleHyperlink methods.
 //
 
+// Currently, only text links are supported.
 STDMETHODIMP BrowserAccessibilityWin::get_anchor(long index, VARIANT* anchor) {
-  return E_NOTIMPL;
+  if (!instance_active() || !IsHyperlink())
+    return E_FAIL;
+
+  // IA2 text links can have only one anchor, that is the text inside them.
+  if (index != 0 || !anchor)
+    return E_INVALIDARG;
+
+  BSTR hypertext = SysAllocString(TextForIAccessibleText().c_str());
+  DCHECK(hypertext);
+  anchor->vt = VT_BSTR;
+  anchor->bstrVal = hypertext;
+
+  // Returning S_FALSE is not mentioned in the IA2 Spec, but it might have been
+  // an oversight.
+  if (!SysStringLen(hypertext))
+    return S_FALSE;
+
+  return S_OK;
 }
-STDMETHODIMP
-BrowserAccessibilityWin::get_anchorTarget(long index, VARIANT* anchor_target) {
-  return E_NOTIMPL;
+
+// Currently, only text links are supported.
+STDMETHODIMP BrowserAccessibilityWin::get_anchorTarget(long index,
+                                                       VARIANT* anchor_target) {
+  if (!instance_active() || !IsHyperlink())
+    return E_FAIL;
+
+  // IA2 text links can have at most one target, that is when they represent an
+  // HTML hyperlink, i.e. an <a> element with a "href" attribute.
+  if (index != 0 || !anchor_target)
+    return E_INVALIDARG;
+
+  BSTR target;
+  if (!(ia_state() & STATE_SYSTEM_LINKED) ||
+      FAILED(GetStringAttributeAsBstr(ui::AX_ATTR_URL, &target))) {
+    target = SysAllocString(L"");
+  }
+  DCHECK(target);
+  anchor_target->vt = VT_BSTR;
+  anchor_target->bstrVal = target;
+
+  // Returning S_FALSE is not mentioned in the IA2 Spec, but it might have been
+  // an oversight.
+  if (!SysStringLen(target))
+    return S_FALSE;
+
+  return S_OK;
 }
+
 STDMETHODIMP BrowserAccessibilityWin::get_startIndex(long* index) {
-  return E_NOTIMPL;
+  if (!instance_active() || !IsHyperlink())
+    return E_FAIL;
+
+  if (!index)
+    return E_INVALIDARG;
+
+  int32 hypertext_offset = 0;
+  const auto parent = GetParent();
+  if (parent) {
+    hypertext_offset =
+        parent->ToBrowserAccessibilityWin()->GetHypertextOffsetFromChild(*this);
+  }
+  *index = static_cast<LONG>(hypertext_offset);
+  return S_OK;
 }
+
 STDMETHODIMP BrowserAccessibilityWin::get_endIndex(long* index) {
-  return E_NOTIMPL;
+  LONG start_index;
+  HRESULT hr = get_startIndex(&start_index);
+  if (hr == S_OK)
+    *index = start_index + 1;
+  return hr;
 }
+
+// This method is deprecated in the IA2 Spec.
 STDMETHODIMP BrowserAccessibilityWin::get_valid(boolean* valid) {
   return E_NOTIMPL;
 }
 
 //
-// IAccessibleAction not implemented.
+// IAccessibleAction mostly not implemented.
 //
 
 STDMETHODIMP BrowserAccessibilityWin::nActions(long* n_actions) {
-  return E_NOTIMPL;
+  if (!instance_active())
+    return E_FAIL;
+
+  if (!n_actions)
+    return E_INVALIDARG;
+
+  // Required for IAccessibleHyperlink::anchor/anchorTarget to work properly.
+  // TODO(nektar): Implement the rest of the logic required by this interface.
+  if (IsHyperlink())
+    *n_actions = 1;
+  else
+    *n_actions = 0;
+  return S_OK;
 }
+
 STDMETHODIMP BrowserAccessibilityWin::doAction(long action_index) {
   return E_NOTIMPL;
 }
@@ -2996,7 +3072,7 @@
 // IServiceProvider methods.
 //
 
-STDMETHODIMP BrowserAccessibilityWin::QueryService(REFGUID guidService,
+STDMETHODIMP BrowserAccessibilityWin::QueryService(REFGUID guid_service,
                                                    REFIID riid,
                                                    void** object) {
   if (!instance_active())
@@ -3008,7 +3084,7 @@
   if (riid == IID_IAccessible2)
     BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility();
 
-  if (guidService == GUID_IAccessibleContentDocument) {
+  if (guid_service == GUID_IAccessibleContentDocument) {
     // Special Mozilla extension: return the accessible for the root document.
     // Screen readers use this to distinguish between a document loaded event
     // on the root document vs on an iframe.
@@ -3016,22 +3092,22 @@
         IID_IAccessible2, object);
   }
 
-  if (guidService == IID_IAccessible ||
-      guidService == IID_IAccessible2 ||
-      guidService == IID_IAccessibleAction ||
-      guidService == IID_IAccessibleApplication ||
-      guidService == IID_IAccessibleHyperlink ||
-      guidService == IID_IAccessibleHypertext ||
-      guidService == IID_IAccessibleImage ||
-      guidService == IID_IAccessibleTable ||
-      guidService == IID_IAccessibleTable2 ||
-      guidService == IID_IAccessibleTableCell ||
-      guidService == IID_IAccessibleText ||
-      guidService == IID_IAccessibleValue ||
-      guidService == IID_ISimpleDOMDocument ||
-      guidService == IID_ISimpleDOMNode ||
-      guidService == IID_ISimpleDOMText ||
-      guidService == GUID_ISimpleDOM) {
+  if (guid_service == IID_IAccessible ||
+      guid_service == IID_IAccessible2 ||
+      guid_service == IID_IAccessibleAction ||
+      guid_service == IID_IAccessibleApplication ||
+      guid_service == IID_IAccessibleHyperlink ||
+      guid_service == IID_IAccessibleHypertext ||
+      guid_service == IID_IAccessibleImage ||
+      guid_service == IID_IAccessibleTable ||
+      guid_service == IID_IAccessibleTable2 ||
+      guid_service == IID_IAccessibleTableCell ||
+      guid_service == IID_IAccessibleText ||
+      guid_service == IID_IAccessibleValue ||
+      guid_service == IID_ISimpleDOMDocument ||
+      guid_service == IID_ISimpleDOMNode ||
+      guid_service == IID_ISimpleDOMText ||
+      guid_service == GUID_ISimpleDOM) {
     return QueryInterface(riid, object);
   }
 
@@ -3155,6 +3231,12 @@
       *object = NULL;
       return E_NOINTERFACE;
     }
+  } else if (iid == IID_IAccessibleHyperlink) {
+    auto ax_object = reinterpret_cast<const BrowserAccessibilityWin*>(this_ptr);
+    if (!ax_object || !ax_object->IsHyperlink()) {
+      *object = nullptr;
+      return E_NOINTERFACE;
+    }
   }
 
   return CComObjectRootBase::InternalQueryInterface(
@@ -3653,6 +3735,19 @@
   }
 }
 
+bool BrowserAccessibilityWin::IsHyperlink() const {
+  int32 hyperlink_index = -1;
+  const auto parent = GetParent();
+  if (parent) {
+    hyperlink_index =
+        parent->ToBrowserAccessibilityWin()->GetHyperlinkIndexFromChild(*this);
+  }
+
+  if (hyperlink_index >= 0)
+    return true;
+  return false;
+}
+
 int32 BrowserAccessibilityWin::GetHyperlinkIndexFromChild(
     const BrowserAccessibilityWin& child) const {
   if (hyperlinks().empty())
diff --git a/content/browser/accessibility/browser_accessibility_win.h b/content/browser/accessibility/browser_accessibility_win.h
index 8d2971b..094fea7 100644
--- a/content/browser/accessibility/browser_accessibility_win.h
+++ b/content/browser/accessibility/browser_accessibility_win.h
@@ -523,15 +523,16 @@
   CONTENT_EXPORT STDMETHODIMP
   get_hyperlinkIndex(long char_index, long* hyperlink_index) override;
 
-  // IAccessibleHyperlink not implemented.
+  // IAccessibleHyperlink methods.
   CONTENT_EXPORT STDMETHODIMP get_anchor(long index, VARIANT* anchor) override;
-  CONTENT_EXPORT STDMETHODIMP
-  get_anchorTarget(long index, VARIANT* anchor_target) override;
+  CONTENT_EXPORT STDMETHODIMP get_anchorTarget(long index,
+                                               VARIANT* anchor_target) override;
   CONTENT_EXPORT STDMETHODIMP get_startIndex(long* index) override;
   CONTENT_EXPORT STDMETHODIMP get_endIndex(long* index) override;
+  // This method is deprecated in the IA2 Spec and so we don't implement it.
   CONTENT_EXPORT STDMETHODIMP get_valid(boolean* valid) override;
 
-  // IAccessibleAction not implemented.
+  // IAccessibleAction mostly not implemented.
   CONTENT_EXPORT STDMETHODIMP nActions(long* n_actions) override;
   CONTENT_EXPORT STDMETHODIMP doAction(long action_index) override;
   CONTENT_EXPORT STDMETHODIMP
@@ -775,11 +776,18 @@
   void IntAttributeToIA2(ui::AXIntAttribute attribute,
                          const char* ia2_attr);
 
-  // Functions that help when retrieving hyperlinks and hypertext offsets.
-  // Return -1 in case of failure.
+  //
+  // Helper methods for IA2 hyperlinks.
+  //
   // Hyperlink is an IA2 misnomer. It refers to objects embedded within other
   // objects, such as a numbered list within a contenteditable div.
-  // Also, text that includes embedded objects is called hypertext.
+  // Also, in IA2, text that includes embedded objects is called hypertext.
+
+  // Returns true if the current object is an IA2 hyperlink.
+  bool IsHyperlink() const;
+
+  // Functions for retrieving offsets for hyperlinks and hypertext.
+  // Return -1 in case of failure.
   int32 GetHyperlinkIndexFromChild(const BrowserAccessibilityWin& child) const;
   int32 GetHypertextOffsetFromHyperlinkIndex(int32 hyperlink_index) const;
   int32 GetHypertextOffsetFromChild(const BrowserAccessibilityWin& child) const;
@@ -792,11 +800,14 @@
   // offset. Otherwise, returns either 0 or the length of the hypertext
   // depending on the direction of the selection.
   // Returns -1 in case of unexpected failure, e.g. the selection endpoint
-  // cannot be located in the accessibility tree.
+  // cannot be found in the accessibility tree.
   int GetHypertextOffsetFromEndpoint(
       const BrowserAccessibilityWin& endpoint_object,
       int endpoint_offset) const;
 
+  //
+  // Selection helper functions.
+  //
   // The following functions retrieve the endpoints of the current selection.
   // First they check for a local selection found on the current control, e.g.
   // when querying the selection on a textarea.
@@ -805,7 +816,7 @@
   int GetSelectionFocus() const;
   // Retrieves the selection offsets in the way required by the IA2 APIs.
   // selection_start and selection_end are -1 when there is no selection active
-  // inside this object.
+  // on this object.
   // The greatest of the two offsets is one past the last character of the
   // selection.)
   void GetSelectionOffsets(int* selection_start, int* selection_end) const;
diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc
index 7b4fbcd..b7a41e77 100644
--- a/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -1205,6 +1205,160 @@
   ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
 }
 
+TEST_F(BrowserAccessibilityTest, TestIAccessibleHyperlink) {
+  ui::AXNodeData root;
+  root.id = 1;
+  root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+  root.state = (1 << ui::AX_STATE_READ_ONLY) | (1 << ui::AX_STATE_FOCUSABLE);
+
+  ui::AXNodeData div;
+  div.id = 2;
+  div.role = ui::AX_ROLE_DIV;
+  div.state = (1 << ui::AX_STATE_FOCUSABLE);
+
+  ui::AXNodeData text;
+  text.id = 3;
+  text.role = ui::AX_ROLE_STATIC_TEXT;
+  text.SetName("Click ");
+
+  ui::AXNodeData link;
+  link.id = 4;
+  link.role = ui::AX_ROLE_LINK;
+  link.state = (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_LINKED);
+  link.SetName("here");
+  link.AddStringAttribute(ui::AX_ATTR_URL, "example.com");
+
+  root.child_ids.push_back(2);
+  div.child_ids.push_back(3);
+  div.child_ids.push_back(4);
+
+  CountedBrowserAccessibility::reset();
+  scoped_ptr<BrowserAccessibilityManager> manager(
+      BrowserAccessibilityManager::Create(
+          MakeAXTreeUpdate(root, div, link, text), nullptr,
+          new CountedBrowserAccessibilityFactory()));
+  ASSERT_EQ(4, CountedBrowserAccessibility::num_instances());
+
+  ASSERT_NE(nullptr, manager->GetRoot());
+  BrowserAccessibilityWin* root_accessible =
+      manager->GetRoot()->ToBrowserAccessibilityWin();
+  ASSERT_NE(nullptr, root_accessible);
+  ASSERT_EQ(1U, root_accessible->PlatformChildCount());
+
+  BrowserAccessibilityWin* div_accessible =
+      root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+  ASSERT_NE(nullptr, div_accessible);
+  ASSERT_EQ(2U, div_accessible->PlatformChildCount());
+
+  BrowserAccessibilityWin* text_accessible =
+      div_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+  ASSERT_NE(nullptr, text_accessible);
+  BrowserAccessibilityWin* link_accessible =
+      div_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+  ASSERT_NE(nullptr, link_accessible);
+
+  // -1 is never a valid value.
+  LONG n_actions = -1;
+  LONG start_index = -1;
+  LONG end_index = -1;
+
+  base::win::ScopedComPtr<IAccessibleHyperlink> hyperlink;
+  base::win::ScopedVariant anchor;
+  base::win::ScopedVariant anchor_target;
+  base::win::ScopedBstr bstr;
+
+  base::string16 div_hypertext(L"Click ");
+  div_hypertext.push_back(BrowserAccessibilityWin::kEmbeddedCharacter);
+
+  // div_accessible and link_accessible are the only IA2 hyperlinks.
+  EXPECT_HRESULT_FAILED(root_accessible->QueryInterface(
+      IID_IAccessibleHyperlink, reinterpret_cast<void**>(hyperlink.Receive())));
+  hyperlink.Release();
+  EXPECT_HRESULT_SUCCEEDED(div_accessible->QueryInterface(
+      IID_IAccessibleHyperlink, reinterpret_cast<void**>(hyperlink.Receive())));
+  hyperlink.Release();
+  EXPECT_HRESULT_FAILED(text_accessible->QueryInterface(
+      IID_IAccessibleHyperlink, reinterpret_cast<void**>(hyperlink.Receive())));
+  hyperlink.Release();
+  EXPECT_HRESULT_SUCCEEDED(link_accessible->QueryInterface(
+      IID_IAccessibleHyperlink, reinterpret_cast<void**>(hyperlink.Receive())));
+  hyperlink.Release();
+
+  EXPECT_HRESULT_SUCCEEDED(root_accessible->nActions(&n_actions));
+  EXPECT_EQ(0, n_actions);
+  EXPECT_HRESULT_SUCCEEDED(div_accessible->nActions(&n_actions));
+  EXPECT_EQ(1, n_actions);
+  EXPECT_HRESULT_SUCCEEDED(text_accessible->nActions(&n_actions));
+  EXPECT_EQ(0, n_actions);
+  EXPECT_HRESULT_SUCCEEDED(link_accessible->nActions(&n_actions));
+  EXPECT_EQ(1, n_actions);
+
+  EXPECT_HRESULT_FAILED(root_accessible->get_anchor(0, anchor.Receive()));
+  anchor.Reset();
+  HRESULT hr = div_accessible->get_anchor(0, anchor.Receive());
+  EXPECT_EQ(S_OK, hr);
+  EXPECT_EQ(VT_BSTR, anchor.type());
+  bstr.Reset(V_BSTR(anchor.ptr()));
+  EXPECT_STREQ(div_hypertext.c_str(), bstr);
+  bstr.Reset();
+  anchor.Reset();
+  EXPECT_HRESULT_FAILED(text_accessible->get_anchor(0, anchor.Receive()));
+  anchor.Reset();
+  hr = link_accessible->get_anchor(0, anchor.Receive());
+  EXPECT_EQ(S_OK, hr);
+  EXPECT_EQ(VT_BSTR, anchor.type());
+  bstr.Reset(V_BSTR(anchor.ptr()));
+  EXPECT_STREQ(L"here", bstr);
+  bstr.Reset();
+  anchor.Reset();
+  EXPECT_HRESULT_FAILED(div_accessible->get_anchor(1, anchor.Receive()));
+  anchor.Reset();
+  EXPECT_HRESULT_FAILED(link_accessible->get_anchor(1, anchor.Receive()));
+  anchor.Reset();
+
+  EXPECT_HRESULT_FAILED(
+      root_accessible->get_anchorTarget(0, anchor_target.Receive()));
+  anchor_target.Reset();
+  hr = div_accessible->get_anchorTarget(0, anchor_target.Receive());
+  EXPECT_EQ(S_FALSE, hr);
+  EXPECT_EQ(VT_BSTR, anchor_target.type());
+  bstr.Reset(V_BSTR(anchor_target.ptr()));
+  // Target should be empty.
+  EXPECT_STREQ(L"", bstr);
+  bstr.Reset();
+  anchor_target.Reset();
+  EXPECT_HRESULT_FAILED(
+      text_accessible->get_anchorTarget(0, anchor_target.Receive()));
+  anchor_target.Reset();
+  hr = link_accessible->get_anchorTarget(0, anchor_target.Receive());
+  EXPECT_EQ(S_OK, hr);
+  EXPECT_EQ(VT_BSTR, anchor_target.type());
+  bstr.Reset(V_BSTR(anchor_target.ptr()));
+  EXPECT_STREQ(L"example.com", bstr);
+  bstr.Reset();
+  anchor_target.Reset();
+  EXPECT_HRESULT_FAILED(
+      div_accessible->get_anchorTarget(1, anchor_target.Receive()));
+  anchor_target.Reset();
+  EXPECT_HRESULT_FAILED(
+      link_accessible->get_anchorTarget(1, anchor_target.Receive()));
+  anchor_target.Reset();
+
+  EXPECT_HRESULT_FAILED(root_accessible->get_startIndex(&start_index));
+  EXPECT_HRESULT_SUCCEEDED(div_accessible->get_startIndex(&start_index));
+  EXPECT_EQ(0, start_index);
+  EXPECT_HRESULT_FAILED(text_accessible->get_startIndex(&start_index));
+  EXPECT_HRESULT_SUCCEEDED(link_accessible->get_startIndex(&start_index));
+  EXPECT_EQ(6, start_index);
+
+  EXPECT_HRESULT_FAILED(root_accessible->get_endIndex(&end_index));
+  EXPECT_HRESULT_SUCCEEDED(div_accessible->get_endIndex(&end_index));
+  EXPECT_EQ(1, end_index);
+  EXPECT_HRESULT_FAILED(text_accessible->get_endIndex(&end_index));
+  EXPECT_HRESULT_SUCCEEDED(link_accessible->get_endIndex(&end_index));
+  EXPECT_EQ(7, end_index);
+}
+
 TEST_F(BrowserAccessibilityTest, TestPlatformDeepestFirstLastChild) {
   ui::AXNodeData root;
   root.id = 1;
diff --git a/content/browser/compositor/delegated_frame_host.cc b/content/browser/compositor/delegated_frame_host.cc
index abc001e..ca8a0d87 100644
--- a/content/browser/compositor/delegated_frame_host.cc
+++ b/content/browser/compositor/delegated_frame_host.cc
@@ -254,7 +254,7 @@
   resize_lock_->UnlockCompositor();
 }
 
-void DelegatedFrameHost::DidReceiveFrameFromRenderer(
+void DelegatedFrameHost::AttemptFrameSubscriberCapture(
     const gfx::Rect& damage_rect) {
   if (!frame_subscriber() || !CanCopyToVideoFrame())
     return;
@@ -298,14 +298,25 @@
   // screenshots) since those copy requests do not specify |frame_subscriber()|
   // as a source.
   request->set_source(frame_subscriber());
-  request->set_area(gfx::Rect(current_frame_size_in_dip_));
   if (subscriber_texture.get()) {
     request->SetTextureMailbox(
         cc::TextureMailbox(subscriber_texture->mailbox(),
                            subscriber_texture->target(),
                            subscriber_texture->sync_point()));
   }
-  RequestCopyOfOutput(request.Pass());
+
+  if (surface_factory_.get()) {
+    // To avoid unnecessary composites, go directly to the Surface rather than
+    // through RequestCopyOfOutput (which goes through the browser
+    // compositor).
+    if (!request_copy_of_output_callback_for_testing_.is_null())
+      request_copy_of_output_callback_for_testing_.Run(request.Pass());
+    else
+      surface_factory_->RequestCopyOfSurface(surface_id_, request.Pass());
+  } else {
+    request->set_area(gfx::Rect(current_frame_size_in_dip_));
+    RequestCopyOfOutput(request.Pass());
+  }
 }
 
 void DelegatedFrameHost::SwapDelegatedFrame(
@@ -475,7 +486,10 @@
   } else {
     AddOnCommitCallbackAndDisableLocks(base::Closure());
   }
-  DidReceiveFrameFromRenderer(damage_rect);
+  // With Surfaces, the notification that the surface will be drawn notifies
+  // the frame subscriber.
+  if (!use_surfaces_)
+    AttemptFrameSubscriberCapture(damage_rect);
   if (frame_provider_.get() || !surface_id_.is_null())
     delegated_frame_evictor_->SwappedFrame(
         client_->DelegatedFrameHostIsVisible());
@@ -536,6 +550,13 @@
     SendReturnedDelegatedResources(last_output_surface_id_);
 }
 
+void DelegatedFrameHost::WillDrawSurface(cc::SurfaceId id,
+                                         const gfx::Rect& damage_rect) {
+  if (id != surface_id_)
+    return;
+  AttemptFrameSubscriberCapture(damage_rect);
+}
+
 void DelegatedFrameHost::EvictDelegatedFrame() {
   client_->DelegatedFrameHostGetLayer()->SetShowSolidColorContent();
   frame_provider_ = NULL;
diff --git a/content/browser/compositor/delegated_frame_host.h b/content/browser/compositor/delegated_frame_host.h
index aa3ce5b1..c9662cbc 100644
--- a/content/browser/compositor/delegated_frame_host.h
+++ b/content/browser/compositor/delegated_frame_host.h
@@ -116,6 +116,7 @@
 
   // cc::SurfaceFactoryClient implementation.
   void ReturnResources(const cc::ReturnedResourceArray& resources) override;
+  void WillDrawSurface(cc::SurfaceId id, const gfx::Rect& damage_rect) override;
 
   bool CanCopyToBitmap() const;
 
@@ -246,7 +247,7 @@
 
   // Called to consult the current |frame_subscriber_|, to determine and maybe
   // initiate a copy-into-video-frame request.
-  void DidReceiveFrameFromRenderer(const gfx::Rect& damage_rect);
+  void AttemptFrameSubscriberCapture(const gfx::Rect& damage_rect);
 
   DelegatedFrameHostClient* const client_;
   ui::Compositor* compositor_;
diff --git a/content/browser/frame_host/cross_process_frame_connector.cc b/content/browser/frame_host/cross_process_frame_connector.cc
index 7fb24a4..be3b397 100644
--- a/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/content/browser/frame_host/cross_process_frame_connector.cc
@@ -7,6 +7,7 @@
 #include "cc/surfaces/surface.h"
 #include "cc/surfaces/surface_manager.h"
 #include "content/browser/compositor/surface_utils.h"
+#include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/render_frame_host_manager.h"
 #include "content/browser/frame_host/render_frame_proxy_host.h"
@@ -163,6 +164,12 @@
     static_cast<RenderWidgetHostViewBase*>(rwhv)->GetScreenInfo(results);
 }
 
+void CrossProcessFrameConnector::UpdateCursor(const WebCursor& cursor) {
+  RenderWidgetHostViewBase* root_view = GetRootRenderWidgetHostView();
+  if (root_view)
+    root_view->UpdateCursor(cursor);
+}
+
 void CrossProcessFrameConnector::OnForwardInputEvent(
     const blink::WebInputEvent* event) {
   if (!view_)
@@ -218,4 +225,14 @@
     view_->SetSize(frame_rect.size());
 }
 
+RenderWidgetHostViewBase*
+CrossProcessFrameConnector::GetRootRenderWidgetHostView() {
+  return static_cast<RenderWidgetHostViewBase*>(
+      frame_proxy_in_parent_renderer_->frame_tree_node()
+          ->frame_tree()
+          ->root()
+          ->current_frame_host()
+          ->GetView());
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/cross_process_frame_connector.h b/content/browser/frame_host/cross_process_frame_connector.h
index 48547213..abe3a04 100644
--- a/content/browser/frame_host/cross_process_frame_connector.h
+++ b/content/browser/frame_host/cross_process_frame_connector.h
@@ -29,7 +29,9 @@
 namespace content {
 class RenderFrameProxyHost;
 class RenderWidgetHostImpl;
+class RenderWidgetHostViewBase;
 class RenderWidgetHostViewChildFrame;
+class WebCursor;
 
 // CrossProcessFrameConnector provides the platform view abstraction for
 // RenderWidgetHostViewChildFrame allowing RWHVChildFrame to remain ignorant
@@ -96,6 +98,7 @@
   gfx::Rect ChildFrameRect();
   float device_scale_factor() const { return device_scale_factor_; }
   void GetScreenInfo(blink::WebScreenInfo* results);
+  void UpdateCursor(const WebCursor& cursor);
 
  private:
   // Handlers for messages received from the parent frame.
@@ -113,6 +116,9 @@
   void SetDeviceScaleFactor(float scale_factor);
   void SetSize(gfx::Rect frame_rect);
 
+  // Retrieve the view for the top-level frame under the same WebContents.
+  RenderWidgetHostViewBase* GetRootRenderWidgetHostView();
+
   // The RenderFrameProxyHost that routes messages to the parent frame's
   // renderer process.
   RenderFrameProxyHost* frame_proxy_in_parent_renderer_;
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
index 0cea2ed1..10370990 100644
--- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -20,6 +20,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/webui/web_ui_impl.h"
 #include "content/common/content_constants_internal.h"
+#include "content/common/input_messages.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
@@ -2115,4 +2116,51 @@
   ResourceDispatcherHost::Get()->SetDelegate(nullptr);
 }
 
+// Tests that InputMsg type IPCs are ignored by swapped out RenderViews. It
+// uses the SetFocus IPC, as RenderView has a CHECK to ensure that condition
+// never happens.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+                       InputMsgToSwappedOutRVHIsIgnored) {
+  StartEmbeddedServer();
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
+
+  // Open a popup to navigate cross-process.
+  Shell* new_shell =
+      OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "foo");
+  EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+            new_shell->web_contents()->GetSiteInstance());
+
+  // Keep a pointer to the RenderViewHost, which will be in swapped out
+  // state after navigating cross-process. This is how this test is causing
+  // a swapped out RenderView to receive InputMsg IPC message.
+  WebContentsImpl* new_web_contents =
+      static_cast<WebContentsImpl*>(new_shell->web_contents());
+  FrameTreeNode* new_root = new_web_contents->GetFrameTree()->root();
+  RenderViewHostImpl* rvh = new_web_contents->GetRenderViewHost();
+
+  // Navigate the popup to a different site, so the |rvh| is swapped out.
+  EXPECT_TRUE(NavigateToURL(
+      new_shell, embedded_test_server()->GetURL("b.com", "/title2.html")));
+  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+            new_shell->web_contents()->GetSiteInstance());
+  EXPECT_EQ(rvh, new_root->render_manager()->GetSwappedOutRenderViewHost(
+                     shell()->web_contents()->GetSiteInstance()));
+
+  // Setup a process observer to ensure there is no crash and send the IPC
+  // message.
+  RenderProcessHostWatcher watcher(
+      rvh->GetProcess(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+  rvh->Send(new InputMsg_SetFocus(rvh->GetRoutingID(), true));
+
+  // The test must wait for a process to exit, but if the IPC message is
+  // properly ignored, there will be no crash. Therefore, navigate the
+  // original window to the same site as the popup, which will just exit the
+  // process cleanly.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title3.html")));
+  watcher.Wait();
+  EXPECT_TRUE(watcher.did_exit_normally());
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc
index 07cd5b53..88bf587 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -162,6 +162,8 @@
 }
 
 void RenderWidgetHostViewChildFrame::UpdateCursor(const WebCursor& cursor) {
+  if (frame_connector_)
+    frame_connector_->UpdateCursor(cursor);
 }
 
 void RenderWidgetHostViewChildFrame::SetIsLoading(bool is_loading) {
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 4920cf2e9..96c864e2 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -387,7 +387,10 @@
   }
 }
 
-void CompositorImpl::SetWindowSurface(ANativeWindow* window) {
+void CompositorImpl::SetSurface(jobject surface) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jobject> j_surface(env, surface);
+
   GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
 
   if (window_) {
@@ -396,9 +399,19 @@
     tracker->RemoveSurface(surface_id_);
     ANativeWindow_release(window_);
     window_ = NULL;
+    UnregisterViewSurface(surface_id_);
     surface_id_ = 0;
   }
 
+  ANativeWindow* window = NULL;
+  if (surface) {
+    // Note: This ensures that any local references used by
+    // ANativeWindow_fromSurface are released immediately. This is needed as a
+    // workaround for https://code.google.com/p/android/issues/detail?id=68174
+    base::android::ScopedJavaLocalFrame scoped_local_reference_frame(env);
+    window = ANativeWindow_fromSurface(env, surface);
+  }
+
   if (window) {
     window_ = window;
     ANativeWindow_acquire(window);
@@ -406,34 +419,10 @@
     tracker->SetSurfaceHandle(
         surface_id_,
         gfx::GLSurfaceHandle(surface_id_, gfx::NATIVE_DIRECT));
-    SetVisible(true);
-  }
-}
-
-void CompositorImpl::SetSurface(jobject surface) {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  base::android::ScopedJavaLocalRef<jobject> j_surface(env, surface);
-
-  // First, shut down the GL context.
-  int surface_id = surface_id_;
-  SetWindowSurface(NULL);
-  // Then, cleanup any existing surface references.
-  if (surface_id)
-    UnregisterViewSurface(surface_id);
-
-  // Now, set the new surface if we have one.
-  ANativeWindow* window = NULL;
-  if (surface) {
-    // Note: This ensures that any local references used by
-    // ANativeWindow_fromSurface are released immediately. This is needed as a
-    // workaround for https://code.google.com/p/android/issues/detail?id=68174
-    base::android::ScopedJavaLocalFrame scoped_local_reference_frame(env);
-    window = ANativeWindow_fromSurface(env, surface);
-  }
-  if (window) {
-    SetWindowSurface(window);
-    ANativeWindow_release(window);
+    // Register first, SetVisible() might create an OutputSurface.
     RegisterViewSurface(surface_id_, j_surface.obj());
+    SetVisible(true);
+    ANativeWindow_release(window);
   }
 }
 
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index fd454db..223ae081 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -119,7 +119,6 @@
                base::TimeDelta vsync_period) override;
   void SetNeedsAnimate() override;
 
-  void SetWindowSurface(ANativeWindow* window);
   void SetVisible(bool visible);
 
   enum CompositingTrigger {
diff --git a/content/browser/renderer_host/input/input_router.h b/content/browser/renderer_host/input/input_router.h
index 027f9fe..186022f 100644
--- a/content/browser/renderer_host/input/input_router.h
+++ b/content/browser/renderer_host/input/input_router.h
@@ -35,8 +35,7 @@
   virtual void SendWheelEvent(
       const MouseWheelEventWithLatencyInfo& wheel_event) = 0;
   virtual void SendKeyboardEvent(
-      const NativeWebKeyboardEventWithLatencyInfo& key_event,
-      bool is_shortcut) = 0;
+      const NativeWebKeyboardEventWithLatencyInfo& key_event) = 0;
   virtual void SendGestureEvent(
       const GestureEventWithLatencyInfo& gesture_event) = 0;
   virtual void SendTouchEvent(
diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc
index ebc0040a..7aabd609 100644
--- a/content/browser/renderer_host/input/input_router_impl.cc
+++ b/content/browser/renderer_host/input/input_router_impl.cc
@@ -152,12 +152,11 @@
   LOCAL_HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize",
                              coalesced_mouse_wheel_events_.size());
 
-  FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency, false);
+  FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency);
 }
 
 void InputRouterImpl::SendKeyboardEvent(
-    const NativeWebKeyboardEventWithLatencyInfo& key_event,
-    bool is_keyboard_shortcut) {
+    const NativeWebKeyboardEventWithLatencyInfo& key_event) {
   // Put all WebKeyboardEvent objects in a queue since we can't trust the
   // renderer and we need to give something to the HandleKeyboardEvent
   // handler.
@@ -167,9 +166,7 @@
   gesture_event_queue_.FlingHasBeenHalted();
 
   // Only forward the non-native portions of our event.
-  FilterAndSendWebInputEvent(key_event.event,
-                             key_event.latency,
-                             is_keyboard_shortcut);
+  FilterAndSendWebInputEvent(key_event.event, key_event.latency);
 }
 
 void InputRouterImpl::SendGestureEvent(
@@ -213,7 +210,7 @@
     current_mouse_move_ = mouse_event;
   }
 
-  FilterAndSendWebInputEvent(mouse_event.event, mouse_event.latency, false);
+  FilterAndSendWebInputEvent(mouse_event.event, mouse_event.latency);
 }
 
 void InputRouterImpl::SendTouchEventImmediately(
@@ -227,12 +224,12 @@
     UpdateTouchAckTimeoutEnabled();
   }
 
-  FilterAndSendWebInputEvent(touch_event.event, touch_event.latency, false);
+  FilterAndSendWebInputEvent(touch_event.event, touch_event.latency);
 }
 
 void InputRouterImpl::SendGestureEventImmediately(
     const GestureEventWithLatencyInfo& gesture_event) {
-  FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
+  FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency);
 }
 
 const NativeWebKeyboardEvent* InputRouterImpl::GetLastKeyboardEvent() const {
@@ -339,8 +336,7 @@
 
 void InputRouterImpl::FilterAndSendWebInputEvent(
     const WebInputEvent& input_event,
-    const ui::LatencyInfo& latency_info,
-    bool is_keyboard_shortcut) {
+    const ui::LatencyInfo& latency_info) {
   TRACE_EVENT1("input",
                "InputRouterImpl::FilterAndSendWebInputEvent",
                "type",
@@ -354,18 +350,17 @@
   // Any input event cancels a pending mouse move event.
   next_mouse_move_.reset();
 
-  OfferToHandlers(input_event, latency_info, is_keyboard_shortcut);
+  OfferToHandlers(input_event, latency_info);
 }
 
 void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event,
-                                      const ui::LatencyInfo& latency_info,
-                                      bool is_keyboard_shortcut) {
+                                      const ui::LatencyInfo& latency_info) {
   output_stream_validator_.Validate(input_event);
 
   if (OfferToClient(input_event, latency_info))
     return;
 
-  OfferToRenderer(input_event, latency_info, is_keyboard_shortcut);
+  OfferToRenderer(input_event, latency_info);
 
   // Touch events should always indicate in the event whether they are
   // cancelable (respect ACK disposition) or not except touchmove.
@@ -416,10 +411,9 @@
 }
 
 bool InputRouterImpl::OfferToRenderer(const WebInputEvent& input_event,
-                                      const ui::LatencyInfo& latency_info,
-                                      bool is_keyboard_shortcut) {
-  if (Send(new InputMsg_HandleInputEvent(
-          routing_id(), &input_event, latency_info, is_keyboard_shortcut))) {
+                                      const ui::LatencyInfo& latency_info) {
+  if (Send(new InputMsg_HandleInputEvent(routing_id(), &input_event,
+                                         latency_info))) {
     // Ack messages for ignored ack event types should never be sent by the
     // renderer. Consequently, such event types should not affect event time
     // or in-flight event count metrics.
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h
index f42adfade..e1ea09a 100644
--- a/content/browser/renderer_host/input/input_router_impl.h
+++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -59,8 +59,8 @@
   void SendMouseEvent(const MouseEventWithLatencyInfo& mouse_event) override;
   void SendWheelEvent(
       const MouseWheelEventWithLatencyInfo& wheel_event) override;
-  void SendKeyboardEvent(const NativeWebKeyboardEventWithLatencyInfo& key_event,
-                         bool is_keyboard_shortcut) override;
+  void SendKeyboardEvent(
+      const NativeWebKeyboardEventWithLatencyInfo& key_event) override;
   void SendGestureEvent(
       const GestureEventWithLatencyInfo& gesture_event) override;
   void SendTouchEvent(const TouchEventWithLatencyInfo& touch_event) override;
@@ -97,19 +97,13 @@
 
   // Filters and forwards |input_event| to the appropriate handler.
   void FilterAndSendWebInputEvent(const blink::WebInputEvent& input_event,
-                                  const ui::LatencyInfo& latency_info,
-                                  bool is_keyboard_shortcut);
+                                  const ui::LatencyInfo& latency_info);
 
   // Utility routine for filtering and forwarding |input_event| to the
   // appropriate handler. |input_event| will be offered to the overscroll
   // controller, client and renderer, in that order.
   void OfferToHandlers(const blink::WebInputEvent& input_event,
-                       const ui::LatencyInfo& latency_info,
-                       bool is_keyboard_shortcut);
-
-  // Returns true if |input_event| was consumed by the overscroll controller.
-  bool OfferToOverscrollController(const blink::WebInputEvent& input_event,
-                                   const ui::LatencyInfo& latency_info);
+                       const ui::LatencyInfo& latency_info);
 
   // Returns true if |input_event| was consumed by the client.
   bool OfferToClient(const blink::WebInputEvent& input_event,
@@ -118,8 +112,7 @@
   // Returns true if |input_event| was successfully sent to the renderer
   // as an async IPC Message.
   bool OfferToRenderer(const blink::WebInputEvent& input_event,
-                       const ui::LatencyInfo& latency_info,
-                       bool is_keyboard_shortcut);
+                       const ui::LatencyInfo& latency_info);
 
   // IPC message handlers
   void OnInputEventAck(const InputEventAck& ack);
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc
index a7b1ba9..2290860 100644
--- a/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -80,12 +80,6 @@
   return *event;
 }
 
-bool GetIsShortcutFromHandleInputEventMessage(const IPC::Message* msg) {
-  InputMsg_HandleInputEvent::Schema::Param param;
-  InputMsg_HandleInputEvent::Read(msg, &param);
-  return base::get<2>(param);
-}
-
 template<typename MSG_T, typename ARG_T1>
 void ExpectIPCMessageWithArg1(const IPC::Message* msg, const ARG_T1& arg1) {
   ASSERT_EQ(MSG_T::ID, msg->type());
@@ -182,12 +176,12 @@
     input_router()->NotifySiteIsMobileOptimized(false);
   }
 
-  void SimulateKeyboardEvent(WebInputEvent::Type type, bool is_shortcut) {
+  void SimulateKeyboardEvent(WebInputEvent::Type type) {
     WebKeyboardEvent event = SyntheticWebKeyboardEventBuilder::Build(type);
     NativeWebKeyboardEvent native_event;
     memcpy(&native_event, &event, sizeof(event));
     NativeWebKeyboardEventWithLatencyInfo key_event(native_event);
-    input_router_->SendKeyboardEvent(key_event, is_shortcut);
+    input_router_->SendKeyboardEvent(key_event);
   }
 
   void SimulateWheelEvent(float dX, float dY, int modifiers, bool precise) {
@@ -617,7 +611,7 @@
   client_->set_filter_state(INPUT_EVENT_ACK_STATE_CONSUMED);
 
   // Simulate a keyboard event.
-  SimulateKeyboardEvent(WebInputEvent::RawKeyDown, false);
+  SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
 
   // Make sure no input event is sent to the renderer.
   EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
@@ -634,7 +628,7 @@
   client_->set_filter_state(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
 
   // Simulate a keyboard event that has no consumer.
-  SimulateKeyboardEvent(WebInputEvent::RawKeyDown, false);
+  SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
 
   // Make sure no input event is sent to the renderer.
   EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
@@ -643,27 +637,15 @@
 
   // Simulate a keyboard event that should be dropped.
   client_->set_filter_state(INPUT_EVENT_ACK_STATE_UNKNOWN);
-  SimulateKeyboardEvent(WebInputEvent::RawKeyDown, false);
+  SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
 
   // Make sure no input event is sent to the renderer, and no ack is sent.
   EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
   EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount());
 }
 
-TEST_F(InputRouterImplTest, ShortcutKeyboardEvent) {
-  SimulateKeyboardEvent(WebInputEvent::RawKeyDown, true);
-  EXPECT_TRUE(GetIsShortcutFromHandleInputEventMessage(
-      process_->sink().GetMessageAt(0)));
-
-  process_->sink().ClearMessages();
-
-  SimulateKeyboardEvent(WebInputEvent::RawKeyDown, false);
-  EXPECT_FALSE(GetIsShortcutFromHandleInputEventMessage(
-      process_->sink().GetMessageAt(0)));
-}
-
 TEST_F(InputRouterImplTest, NoncorrespondingKeyEvents) {
-  SimulateKeyboardEvent(WebInputEvent::RawKeyDown, false);
+  SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
 
   SendInputEventACK(WebInputEvent::KeyUp,
                     INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
@@ -674,7 +656,7 @@
 
 TEST_F(InputRouterImplTest, HandleKeyEventsWeSent) {
   // Simulate a keyboard event.
-  SimulateKeyboardEvent(WebInputEvent::RawKeyDown, false);
+  SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
   ASSERT_TRUE(input_router_->GetLastKeyboardEvent());
   EXPECT_EQ(WebInputEvent::RawKeyDown,
             input_router_->GetLastKeyboardEvent()->type);
diff --git a/content/browser/renderer_host/input/mock_input_router_client.cc b/content/browser/renderer_host/input/mock_input_router_client.cc
index fcb5de1..07d3d179 100644
--- a/content/browser/renderer_host/input/mock_input_router_client.cc
+++ b/content/browser/renderer_host/input/mock_input_router_client.cc
@@ -33,7 +33,7 @@
     const WebInputEvent& input_event,
     const ui::LatencyInfo& latency_info) {
   filter_input_event_called_ = true;
-  last_filter_event_.reset(new InputEvent(input_event, latency_info, false));
+  last_filter_event_.reset(new InputEvent(input_event, latency_info));
   return filter_state_;
 }
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 8b96d457..c89173a 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1351,6 +1351,7 @@
     switches::kVModule,
     // Please keep these in alphabetical order. Compositor switches here should
     // also be added to chrome/browser/chromeos/login/chrome_restart_request.cc.
+    cc::switches::kDisableCachedPictureRaster,
     cc::switches::kDisableCompositedAntialiasing,
     cc::switches::kDisableMainFrameBeforeActivation,
     cc::switches::kDisableThreadedAnimation,
@@ -1705,6 +1706,17 @@
     DCHECK(!deleting_soon_);
 
     DCHECK_EQ(0, pending_views_);
+
+    // If |channel_| is still valid, the process associated with this
+    // RenderProcessHost is still alive. Notify all observers that the process
+    // has exited cleanly, even though it will be destroyed a bit later.
+    // Observers shouldn't rely on this process anymore.
+    if (channel_.get()) {
+      FOR_EACH_OBSERVER(
+          RenderProcessHostObserver, observers_,
+          RenderProcessExited(this, base::TERMINATION_STATUS_NORMAL_TERMINATION,
+                              0));
+    }
     FOR_EACH_OBSERVER(RenderProcessHostObserver, observers_,
                       RenderProcessHostDestroyed(this));
     NotificationService::current()->Notify(
@@ -1729,6 +1741,14 @@
 
     RemoveUserData(kSessionStorageHolderKey);
 
+    // On shutdown, |this| may not be deleted because the deleter is posted to
+    // the current MessageLoop, but MessageLoop deletes all its pending
+    // callbacks on shutdown. Since the deleter takes |this| as a raw pointer,
+    // deleting the callback doesn't delete |this| resulting in a memory leak.
+    // Valgrind complains, so delete |mojo_application_host_| explicitly here to
+    // stop valgrind from complaining.
+    mojo_application_host_.reset();
+
     // Remove ourself from the list of renderer processes so that we can't be
     // reused in between now and when the Delete task runs.
     UnregisterHost(GetID());
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 512dfee..0b86c70 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1145,8 +1145,9 @@
     return;
 
   NativeWebKeyboardEventWithLatencyInfo key_event_with_latency(key_event);
+  key_event_with_latency.event.isBrowserShortcut = is_shortcut;
   latency_tracker_.OnInputEvent(key_event, &key_event_with_latency.latency);
-  input_router_->SendKeyboardEvent(key_event_with_latency, is_shortcut);
+  input_router_->SendKeyboardEvent(key_event_with_latency);
 }
 
 void RenderWidgetHostImpl::QueueSyntheticGesture(
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 2503b5e..9d95b9a 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -55,6 +55,22 @@
 
 namespace content {
 
+std::string GetInputMessageTypes(MockRenderProcessHost* process) {
+  std::string result;
+  for (size_t i = 0; i < process->sink().message_count(); ++i) {
+    const IPC::Message* message = process->sink().GetMessageAt(i);
+    EXPECT_EQ(InputMsg_HandleInputEvent::ID, message->type());
+    InputMsg_HandleInputEvent::Param params;
+    EXPECT_TRUE(InputMsg_HandleInputEvent::Read(message, &params));
+    const WebInputEvent* event = base::get<0>(params);
+    if (i != 0)
+      result += " ";
+    result += WebInputEventTraits::GetName(event->type);
+  }
+  process->sink().ClearMessages();
+  return result;
+}
+
 // MockInputRouter -------------------------------------------------------------
 
 class MockInputRouter : public InputRouter {
@@ -83,8 +99,8 @@
       const MouseWheelEventWithLatencyInfo& wheel_event) override {
     sent_wheel_event_ = true;
   }
-  void SendKeyboardEvent(const NativeWebKeyboardEventWithLatencyInfo& key_event,
-                         bool is_shortcut) override {
+  void SendKeyboardEvent(
+      const NativeWebKeyboardEventWithLatencyInfo& key_event) override {
     sent_keyboard_event_ = true;
   }
   void SendGestureEvent(
@@ -327,13 +343,13 @@
  public:
   MockRenderWidgetHostDelegate()
       : prehandle_keyboard_event_(false),
+        prehandle_keyboard_event_is_shortcut_(false),
         prehandle_keyboard_event_called_(false),
         prehandle_keyboard_event_type_(WebInputEvent::Undefined),
         unhandled_keyboard_event_called_(false),
         unhandled_keyboard_event_type_(WebInputEvent::Undefined),
         handle_wheel_event_(false),
-        handle_wheel_event_called_(false) {
-  }
+        handle_wheel_event_called_(false) {}
   ~MockRenderWidgetHostDelegate() override {}
 
   // Tests that make sure we ignore keyboard event acknowledgments to events we
@@ -362,15 +378,18 @@
     handle_wheel_event_ = handle;
   }
 
-  bool handle_wheel_event_called() {
-    return handle_wheel_event_called_;
+  void set_prehandle_keyboard_event_is_shortcut(bool is_shortcut) {
+    prehandle_keyboard_event_is_shortcut_ = is_shortcut;
   }
 
+  bool handle_wheel_event_called() const { return handle_wheel_event_called_; }
+
  protected:
   bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
                               bool* is_keyboard_shortcut) override {
     prehandle_keyboard_event_type_ = event.type;
     prehandle_keyboard_event_called_ = true;
+    *is_keyboard_shortcut = prehandle_keyboard_event_is_shortcut_;
     return prehandle_keyboard_event_;
   }
 
@@ -391,6 +410,7 @@
 
  private:
   bool prehandle_keyboard_event_;
+  bool prehandle_keyboard_event_is_shortcut_;
   bool prehandle_keyboard_event_called_;
   WebInputEvent::Type prehandle_keyboard_event_type_;
 
@@ -891,7 +911,7 @@
 }
 
 TEST_F(RenderWidgetHostTest, PreHandleRawKeyDownEvent) {
-  // Simluate the situation that the browser handled the key down event during
+  // Simulate the situation that the browser handled the key down event during
   // pre-handle phrase.
   delegate_->set_prehandle_keyboard_event(true);
   process_->sink().ClearMessages();
@@ -932,6 +952,59 @@
   EXPECT_EQ(WebInputEvent::KeyUp, delegate_->unhandled_keyboard_event_type());
 }
 
+TEST_F(RenderWidgetHostTest, RawKeyDownShortcutEvent) {
+  // Simulate the situation that the browser marks the key down as a keyboard
+  // shortcut, but doesn't consume it in the pre-handle phase.
+  delegate_->set_prehandle_keyboard_event_is_shortcut(true);
+  process_->sink().ClearMessages();
+
+  // Simulate a keyboard event.
+  SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
+
+  EXPECT_TRUE(delegate_->prehandle_keyboard_event_called());
+  EXPECT_EQ(WebInputEvent::RawKeyDown,
+            delegate_->prehandle_keyboard_event_type());
+
+  // Make sure the RawKeyDown event is sent to the renderer.
+  EXPECT_EQ(1U, process_->sink().message_count());
+  EXPECT_EQ("RawKeyDown", GetInputMessageTypes(process_));
+  process_->sink().ClearMessages();
+
+  // Send the simulated response from the renderer back.
+  SendInputEventACK(WebInputEvent::RawKeyDown,
+                    INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+  EXPECT_EQ(WebInputEvent::RawKeyDown,
+            delegate_->unhandled_keyboard_event_type());
+
+  // The browser won't pre-handle a Char event.
+  delegate_->set_prehandle_keyboard_event_is_shortcut(false);
+
+  // Forward the Char event.
+  SimulateKeyboardEvent(WebInputEvent::Char);
+
+  // The Char event is not suppressed; the renderer will ignore it
+  // if the preceding RawKeyDown shortcut goes unhandled.
+  EXPECT_EQ(1U, process_->sink().message_count());
+  EXPECT_EQ("Char", GetInputMessageTypes(process_));
+  process_->sink().ClearMessages();
+
+  // Send the simulated response from the renderer back.
+  SendInputEventACK(WebInputEvent::Char, INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+  EXPECT_EQ(WebInputEvent::Char, delegate_->unhandled_keyboard_event_type());
+
+  // Forward the KeyUp event.
+  SimulateKeyboardEvent(WebInputEvent::KeyUp);
+
+  // Make sure only KeyUp was sent to the renderer.
+  EXPECT_EQ(1U, process_->sink().message_count());
+  EXPECT_EQ("KeyUp", GetInputMessageTypes(process_));
+  process_->sink().ClearMessages();
+
+  // Send the simulated response from the renderer back.
+  SendInputEventACK(WebInputEvent::KeyUp, INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+  EXPECT_EQ(WebInputEvent::KeyUp, delegate_->unhandled_keyboard_event_type());
+}
+
 TEST_F(RenderWidgetHostTest, UnhandledWheelEvent) {
   SimulateWheelEvent(-5, 0, 0, true);
 
@@ -1134,22 +1207,6 @@
   EXPECT_TRUE(host_->new_content_rendering_timeout_fired());
 }
 
-std::string GetInputMessageTypes(RenderWidgetHostProcess* process) {
-  std::string result;
-  for (size_t i = 0; i < process->sink().message_count(); ++i) {
-    const IPC::Message *message = process->sink().GetMessageAt(i);
-    EXPECT_EQ(InputMsg_HandleInputEvent::ID, message->type());
-    InputMsg_HandleInputEvent::Param params;
-    EXPECT_TRUE(InputMsg_HandleInputEvent::Read(message, &params));
-    const WebInputEvent* event = base::get<0>(params);
-    if (i != 0)
-      result += " ";
-    result += WebInputEventTraits::GetName(event->type);
-  }
-  process->sink().ClearMessages();
-  return result;
-}
-
 TEST_F(RenderWidgetHostTest, TouchEmulator) {
   simulated_event_time_delta_seconds_ = 0.1;
   // Immediately ack all touches instead of sending them to the renderer.
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 0b09f0f..9145cc0 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -21,6 +21,7 @@
 #include "content/browser/compositor/resize_lock.h"
 #include "content/browser/compositor/test/no_transport_image_transport_factory.h"
 #include "content/browser/frame_host/render_widget_host_view_guest.h"
+#include "content/browser/gpu/compositor_util.h"
 #include "content/browser/renderer_host/input/input_router.h"
 #include "content/browser/renderer_host/input/web_input_event_util.h"
 #include "content/browser/renderer_host/overscroll_controller.h"
@@ -192,12 +193,14 @@
 class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
  public:
   FakeFrameSubscriber(gfx::Size size, base::Callback<void(bool)> callback)
-      : size_(size), callback_(callback) {}
+      : size_(size), callback_(callback), should_capture_(true) {}
 
   bool ShouldCaptureFrame(const gfx::Rect& damage_rect,
                           base::TimeTicks present_time,
                           scoped_refptr<media::VideoFrame>* storage,
                           DeliverFrameCallback* callback) override {
+    if (!should_capture_)
+      return false;
     last_present_time_ = present_time;
     *storage = media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_YV12, size_,
                                               gfx::Rect(size_), size_,
@@ -208,6 +211,10 @@
 
   base::TimeTicks last_present_time() const { return last_present_time_; }
 
+  void set_should_capture(bool should_capture) {
+    should_capture_ = should_capture;
+  }
+
   static void CallbackMethod(base::Callback<void(bool)> callback,
                              base::TimeTicks present_time,
                              bool success) {
@@ -218,6 +225,7 @@
   gfx::Size size_;
   base::Callback<void(bool)> callback_;
   base::TimeTicks last_present_time_;
+  bool should_capture_;
 };
 
 class FakeWindowEventDispatcher : public aura::WindowEventDispatcher {
@@ -2236,7 +2244,10 @@
   void RunLoopUntilCallback() {
     base::RunLoop run_loop;
     quit_closure_ = run_loop.QuitClosure();
+    // Temporarily ignore real draw requests.
+    frame_subscriber_->set_should_capture(false);
     run_loop.Run();
+    frame_subscriber_->set_should_capture(true);
   }
 
   void InitializeView() {
@@ -2268,6 +2279,10 @@
   void OnSwapCompositorFrame() {
     view_->OnSwapCompositorFrame(
         1, MakeDelegatedFrame(1.f, view_rect_.size(), view_rect_));
+    cc::SurfaceId surface_id =
+        view_->GetDelegatedFrameHost()->SurfaceIdForTesting();
+    if (!surface_id.is_null())
+      view_->GetDelegatedFrameHost()->WillDrawSurface(surface_id, view_rect_);
     ASSERT_TRUE(view_->last_copy_request_);
   }
 
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
index 5a0ec418..7a5afa3 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -927,7 +927,7 @@
         break;
     }
     DCHECK(message);
-    base::Tuple<IPC::WebInputEventPointer, ui::LatencyInfo, bool> data;
+    base::Tuple<IPC::WebInputEventPointer, ui::LatencyInfo> data;
     InputMsg_HandleInputEvent::Read(message, &data);
     IPC::WebInputEventPointer ipc_event = base::get<0>(data);
     const blink::WebGestureEvent* gesture_event =
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 0896a67..22d3500e1 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -24,6 +24,7 @@
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
+#include "content/common/view_messages.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
@@ -3515,4 +3516,85 @@
   EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame());
 }
 
+// There are no cursors on Android.
+#if !defined(OS_ANDROID)
+class CursorMessageFilter : public content::BrowserMessageFilter {
+ public:
+  CursorMessageFilter()
+      : content::BrowserMessageFilter(ViewMsgStart),
+        message_loop_runner_(new content::MessageLoopRunner),
+        last_set_cursor_routing_id_(MSG_ROUTING_NONE) {}
+
+  bool OnMessageReceived(const IPC::Message& message) override {
+    if (message.type() == ViewHostMsg_SetCursor::ID) {
+      content::BrowserThread::PostTask(
+          content::BrowserThread::UI, FROM_HERE,
+          base::Bind(&CursorMessageFilter::OnSetCursor, this,
+                     message.routing_id()));
+    }
+    return false;
+  }
+
+  void OnSetCursor(int routing_id) {
+    last_set_cursor_routing_id_ = routing_id;
+    message_loop_runner_->Quit();
+  }
+
+  int last_set_cursor_routing_id() const { return last_set_cursor_routing_id_; }
+
+  void Wait() {
+    last_set_cursor_routing_id_ = MSG_ROUTING_NONE;
+    message_loop_runner_->Run();
+  }
+
+ private:
+  ~CursorMessageFilter() override {}
+
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+  int last_set_cursor_routing_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(CursorMessageFilter);
+};
+
+// Verify that we receive a mouse cursor update message when we mouse over
+// a text field contained in an out-of-process iframe.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+                       CursorUpdateFromReceivedFromCrossSiteIframe) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+
+  FrameTreeNode* child_node = root->child_at(0);
+  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  scoped_refptr<CursorMessageFilter> filter = new CursorMessageFilter();
+  child_node->current_frame_host()->GetProcess()->AddFilter(filter.get());
+
+  // Send a MouseMove to the subframe. The frame contains text, and moving the
+  // mouse over it should cause the renderer to send a mouse cursor update.
+  blink::WebMouseEvent mouse_event;
+  mouse_event.type = blink::WebInputEvent::MouseMove;
+  mouse_event.x = 60;
+  mouse_event.y = 60;
+  RenderWidgetHost* rwh_child =
+      root->child_at(0)->current_frame_host()->GetRenderWidgetHost();
+  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  static_cast<WebContentsImpl*>(shell()->web_contents())
+      ->GetInputEventRouter()
+      ->RouteMouseEvent(root_view, &mouse_event);
+
+  // CursorMessageFilter::Wait() implicitly tests whether we receive a
+  // ViewHostMsg_SetCursor message from the renderer process, because it does
+  // does not return otherwise.
+  filter->Wait();
+  EXPECT_EQ(filter->last_set_cursor_routing_id(), rwh_child->GetRoutingID());
+}
+#endif
+
 }  // namespace content
diff --git a/content/common/input/input_event.cc b/content/common/input/input_event.cc
index 93e96911..ab20010 100644
--- a/content/common/input/input_event.cc
+++ b/content/common/input/input_event.cc
@@ -8,14 +8,12 @@
 
 namespace content {
 
-InputEvent::InputEvent() : is_keyboard_shortcut(false) {}
+InputEvent::InputEvent() {}
 
 InputEvent::InputEvent(const blink::WebInputEvent& web_event,
-                       const ui::LatencyInfo& latency_info,
-                       bool is_keyboard_shortcut)
-     : web_event(WebInputEventTraits::Clone(web_event)),
-       latency_info(latency_info),
-       is_keyboard_shortcut(is_keyboard_shortcut) {}
+                       const ui::LatencyInfo& latency_info)
+    : web_event(WebInputEventTraits::Clone(web_event)),
+      latency_info(latency_info) {}
 
 InputEvent::~InputEvent() {}
 
diff --git a/content/common/input/input_event.h b/content/common/input/input_event.h
index 4c13e061..71a3f2b 100644
--- a/content/common/input/input_event.h
+++ b/content/common/input/input_event.h
@@ -22,13 +22,11 @@
  public:
   InputEvent();
   InputEvent(const blink::WebInputEvent& web_event,
-             const ui::LatencyInfo& latency_info,
-             bool is_keyboard_shortcut);
+             const ui::LatencyInfo& latency_info);
   ~InputEvent();
 
   ScopedWebInputEvent web_event;
   ui::LatencyInfo latency_info;
-  bool is_keyboard_shortcut;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(InputEvent);
diff --git a/content/common/input/input_param_traits_unittest.cc b/content/common/input/input_param_traits_unittest.cc
index 784278a..238aff7c 100644
--- a/content/common/input/input_param_traits_unittest.cc
+++ b/content/common/input/input_param_traits_unittest.cc
@@ -30,7 +30,6 @@
     }
     EXPECT_EQ(a->latency_info.latency_components().size(),
               b->latency_info.latency_components().size());
-    EXPECT_EQ(a->is_keyboard_shortcut, b->is_keyboard_shortcut);
   }
 
   static void Compare(const InputEvents* a, const InputEvents* b) {
@@ -163,30 +162,30 @@
   blink::WebKeyboardEvent key_event;
   key_event.type = blink::WebInputEvent::RawKeyDown;
   key_event.nativeKeyCode = 5;
-  events.push_back(new InputEvent(key_event, latency, false));
+  events.push_back(new InputEvent(key_event, latency));
 
   blink::WebMouseWheelEvent wheel_event;
   wheel_event.type = blink::WebInputEvent::MouseWheel;
   wheel_event.deltaX = 10;
   latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 1, 1);
-  events.push_back(new InputEvent(wheel_event, latency, false));
+  events.push_back(new InputEvent(wheel_event, latency));
 
   blink::WebMouseEvent mouse_event;
   mouse_event.type = blink::WebInputEvent::MouseDown;
   mouse_event.x = 10;
   latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 2, 2);
-  events.push_back(new InputEvent(mouse_event, latency, false));
+  events.push_back(new InputEvent(mouse_event, latency));
 
   blink::WebGestureEvent gesture_event;
   gesture_event.type = blink::WebInputEvent::GestureScrollBegin;
   gesture_event.x = -1;
-  events.push_back(new InputEvent(gesture_event, latency, false));
+  events.push_back(new InputEvent(gesture_event, latency));
 
   blink::WebTouchEvent touch_event;
   touch_event.type = blink::WebInputEvent::TouchStart;
   touch_event.touchesLength = 1;
   touch_event.touches[0].radiusX = 1;
-  events.push_back(new InputEvent(touch_event, latency, false));
+  events.push_back(new InputEvent(touch_event, latency));
 
   Verify(events);
 }
diff --git a/content/common/input_messages.h b/content/common/input_messages.h
index 85796f71..b7bb586a 100644
--- a/content/common/input_messages.h
+++ b/content/common/input_messages.h
@@ -72,7 +72,6 @@
 IPC_STRUCT_TRAITS_BEGIN(content::InputEvent)
   IPC_STRUCT_TRAITS_MEMBER(web_event)
   IPC_STRUCT_TRAITS_MEMBER(latency_info)
-  IPC_STRUCT_TRAITS_MEMBER(is_keyboard_shortcut)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(content::SyntheticGestureParams)
@@ -116,10 +115,9 @@
 IPC_STRUCT_TRAITS_END()
 
 // Sends an input event to the render widget.
-IPC_MESSAGE_ROUTED3(InputMsg_HandleInputEvent,
+IPC_MESSAGE_ROUTED2(InputMsg_HandleInputEvent,
                     IPC::WebInputEventPointer /* event */,
-                    ui::LatencyInfo /* latency_info */,
-                    bool /* is_keyboard_shortcut */)
+                    ui::LatencyInfo /* latency_info */)
 
 // Sends the cursor visibility state to the render widget.
 IPC_MESSAGE_ROUTED1(InputMsg_CursorVisibilityChange,
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index 212ba04a..e170e34 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -215,8 +215,6 @@
         'shell/renderer/layout_test/blink_test_helpers.h',
         'shell/renderer/layout_test/blink_test_runner.cc',
         'shell/renderer/layout_test/blink_test_runner.h',
-        'shell/renderer/layout_test/gc_controller.cc',
-        'shell/renderer/layout_test/gc_controller.h',
         'shell/renderer/layout_test/layout_test_content_renderer_client.cc',
         'shell/renderer/layout_test/layout_test_content_renderer_client.h',
         'shell/renderer/layout_test/layout_test_render_frame_observer.cc',
diff --git a/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java b/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java
index e6f6bc0..a5bced2 100644
--- a/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java
+++ b/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java
@@ -333,7 +333,7 @@
         try {
             return mCallback.getViewSurface(surfaceId).getSurface();
         } catch (RemoteException e) {
-            Log.e(TAG, "Unable to call establishSurfaceTexturePeer: %s", e);
+            Log.e(TAG, "Unable to call getViewSurface: %s", e);
             return null;
         }
     }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
index 932d4a4..1817443 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
@@ -12,6 +12,7 @@
 import android.text.TextUtils;
 
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content.browser.test.util.Criteria;
@@ -175,6 +176,7 @@
         assertWaitForPastePopupStatus(false);
     }
 
+    @DisabledTest // http://crbug.com/543682
     @SmallTest
     @Feature({"TextInput"})
     public void testPastePopupNotShownOnLongPressingReadOnlyInput() throws Throwable {
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index ace7157..6497faf 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -83,10 +83,6 @@
 // features.
 const char kDisableBlinkFeatures[]          = "disable-blink-features";
 
-// Disable the creation of compositing layers when it would prevent LCD text.
-const char kDisablePreferCompositingToLCDText[] =
-    "disable-prefer-compositing-to-lcd-text";
-
 // Disables HTML5 DB support.
 const char kDisableDatabases[]              = "disable-databases";
 
@@ -216,6 +212,10 @@
 // --extra-plugin-dir and --load-plugin switches.
 const char kDisablePluginsDiscovery[]       = "disable-plugins-discovery";
 
+// Disable the creation of compositing layers when it would prevent LCD text.
+const char kDisablePreferCompositingToLCDText[] =
+    "disable-prefer-compositing-to-lcd-text";
+
 // Disables the Presentation API.
 const char kDisablePresentationAPI[]        = "disable-presentation-api";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 5d47e85..32a67e04 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -34,7 +34,6 @@
 CONTENT_EXPORT extern const char kDisableAcceleratedMjpegDecode[];
 CONTENT_EXPORT extern const char kDisableAcceleratedVideoDecode[];
 extern const char kDisableBackingStoreLimit[];
-CONTENT_EXPORT extern const char kDisablePreferCompositingToLCDText[];
 CONTENT_EXPORT extern const char kDisableDatabases[];
 CONTENT_EXPORT extern const char kDisableDelayAgnosticAec[];
 extern const char kDisableDirectNPAPIRequests[];
@@ -60,6 +59,7 @@
 CONTENT_EXPORT extern const char kDisableHideInactiveStackedTabCloseButtons[];
 extern const char kDisableHistogramCustomizer[];
 CONTENT_EXPORT extern const char kDisableLCDText[];
+CONTENT_EXPORT extern const char kDisablePreferCompositingToLCDText[];
 CONTENT_EXPORT extern const char kEnablePrefixedEncryptedMedia[];
 extern const char kDisableKillAfterBadIPC[];
 CONTENT_EXPORT extern const char kDisableLocalStorage[];
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index 4c14407..c465364e 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -318,14 +318,14 @@
     const blink::WebKeyboardEvent& key_event) {
   RenderViewImpl* impl = static_cast<RenderViewImpl*>(view_);
   impl->OnMessageReceived(
-      InputMsg_HandleInputEvent(0, &key_event, ui::LatencyInfo(), false));
+      InputMsg_HandleInputEvent(0, &key_event, ui::LatencyInfo()));
 }
 
 void RenderViewTest::SendWebMouseEvent(
     const blink::WebMouseEvent& mouse_event) {
   RenderViewImpl* impl = static_cast<RenderViewImpl*>(view_);
   impl->OnMessageReceived(
-      InputMsg_HandleInputEvent(0, &mouse_event, ui::LatencyInfo(), false));
+      InputMsg_HandleInputEvent(0, &mouse_event, ui::LatencyInfo()));
 }
 
 const char* const kGetCoordinatesScript =
@@ -392,10 +392,10 @@
   mouse_event.clickCount = 1;
   RenderViewImpl* impl = static_cast<RenderViewImpl*>(view_);
   impl->OnMessageReceived(
-      InputMsg_HandleInputEvent(0, &mouse_event, ui::LatencyInfo(), false));
+      InputMsg_HandleInputEvent(0, &mouse_event, ui::LatencyInfo()));
   mouse_event.type = WebInputEvent::MouseUp;
   impl->OnMessageReceived(
-      InputMsg_HandleInputEvent(0, &mouse_event, ui::LatencyInfo(), false));
+      InputMsg_HandleInputEvent(0, &mouse_event, ui::LatencyInfo()));
 }
 
 
@@ -416,10 +416,10 @@
   mouse_event.clickCount = 1;
   RenderViewImpl* impl = static_cast<RenderViewImpl*>(view_);
   impl->OnMessageReceived(
-      InputMsg_HandleInputEvent(0, &mouse_event, ui::LatencyInfo(), false));
+      InputMsg_HandleInputEvent(0, &mouse_event, ui::LatencyInfo()));
   mouse_event.type = WebInputEvent::MouseUp;
   impl->OnMessageReceived(
-      InputMsg_HandleInputEvent(0, &mouse_event, ui::LatencyInfo(), false));
+      InputMsg_HandleInputEvent(0, &mouse_event, ui::LatencyInfo()));
 }
 
 void RenderViewTest::SimulateRectTap(const gfx::Rect& rect) {
@@ -432,7 +432,7 @@
   gesture_event.type = WebInputEvent::GestureTap;
   RenderViewImpl* impl = static_cast<RenderViewImpl*>(view_);
   impl->OnMessageReceived(
-      InputMsg_HandleInputEvent(0, &gesture_event, ui::LatencyInfo(), false));
+      InputMsg_HandleInputEvent(0, &gesture_event, ui::LatencyInfo()));
   impl->FocusChangeComplete();
 }
 
diff --git a/content/renderer/idle_user_detector.cc b/content/renderer/idle_user_detector.cc
index dff78d1..339f68a 100644
--- a/content/renderer/idle_user_detector.cc
+++ b/content/renderer/idle_user_detector.cc
@@ -26,8 +26,7 @@
 }
 
 void IdleUserDetector::OnHandleInputEvent(const blink::WebInputEvent* event,
-                                          const ui::LatencyInfo& latency_info,
-                                          bool is_keyboard_shortcut) {
+                                          const ui::LatencyInfo& latency_info) {
   if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) {
     RenderThreadImpl* render_thread = RenderThreadImpl::current();
     if (render_thread != NULL) {
diff --git a/content/renderer/idle_user_detector.h b/content/renderer/idle_user_detector.h
index 054ead8..58e7037 100644
--- a/content/renderer/idle_user_detector.h
+++ b/content/renderer/idle_user_detector.h
@@ -30,8 +30,7 @@
   bool OnMessageReceived(const IPC::Message& message) override;
 
   void OnHandleInputEvent(const blink::WebInputEvent* event,
-                          const ui::LatencyInfo& latency_info,
-                          bool is_keyboard_shortcut);
+                          const ui::LatencyInfo& latency_info);
 
   DISALLOW_COPY_AND_ASSIGN(IdleUserDetector);
 };
diff --git a/content/renderer/input/input_event_filter.cc b/content/renderer/input/input_event_filter.cc
index 931b4e7..6b648c7 100644
--- a/content/renderer/input/input_event_filter.cc
+++ b/content/renderer/input/input_event_filter.cc
@@ -147,7 +147,6 @@
     return;
   const WebInputEvent* event = base::get<0>(params);
   ui::LatencyInfo latency_info = base::get<1>(params);
-  bool is_keyboard_shortcut = base::get<2>(params);
   DCHECK(event);
 
   const bool send_ack = WebInputEventTraits::WillReceiveAckFromRenderer(*event);
@@ -167,8 +166,8 @@
         "input",
         "InputEventFilter::ForwardToHandler::ForwardToMainListener",
         TRACE_EVENT_SCOPE_THREAD);
-    IPC::Message new_msg = InputMsg_HandleInputEvent(
-        routing_id, event, latency_info, is_keyboard_shortcut);
+    IPC::Message new_msg =
+        InputMsg_HandleInputEvent(routing_id, event, latency_info);
     main_task_runner_->PostTask(FROM_HERE, base::Bind(main_listener_, new_msg));
     return;
   }
diff --git a/content/renderer/input/input_event_filter_unittest.cc b/content/renderer/input/input_event_filter_unittest.cc
index e96cd7a..d072303 100644
--- a/content/renderer/input/input_event_filter_unittest.cc
+++ b/content/renderer/input/input_event_filter_unittest.cc
@@ -113,9 +113,8 @@
                        size_t count) {
   std::vector<IPC::Message> messages;
   for (size_t i = 0; i < count; ++i) {
-    messages.push_back(
-        InputMsg_HandleInputEvent(
-            kTestRoutingID, &events[i], ui::LatencyInfo(), false));
+    messages.push_back(InputMsg_HandleInputEvent(kTestRoutingID, &events[i],
+                                                 ui::LatencyInfo()));
   }
 
   AddMessagesToFilter(message_filter, messages);
@@ -251,10 +250,8 @@
       SyntheticWebMouseEventBuilder::Build(WebMouseEvent::MouseUp);
 
   std::vector<IPC::Message> messages;
-  messages.push_back(InputMsg_HandleInputEvent(kTestRoutingID,
-                                              &mouse_down,
-                                              ui::LatencyInfo(),
-                                              false));
+  messages.push_back(InputMsg_HandleInputEvent(kTestRoutingID, &mouse_down,
+                                               ui::LatencyInfo()));
   // Control where input events are delivered.
   messages.push_back(InputMsg_MouseCaptureLost(kTestRoutingID));
   messages.push_back(InputMsg_SetFocus(kTestRoutingID, true));
@@ -280,10 +277,8 @@
                                          gfx::Point(), gfx::Point()));
   messages.push_back(InputMsg_MoveCaret(kTestRoutingID, gfx::Point()));
 
-  messages.push_back(InputMsg_HandleInputEvent(kTestRoutingID,
-                                              &mouse_up,
-                                              ui::LatencyInfo(),
-                                              false));
+  messages.push_back(
+      InputMsg_HandleInputEvent(kTestRoutingID, &mouse_up, ui::LatencyInfo()));
   AddMessagesToFilter(filter_.get(), messages);
 
   // We should have sent all messages back to the main thread and preserved
diff --git a/content/renderer/media/android/audio_decoder_android.cc b/content/renderer/media/android/audio_decoder_android.cc
index 73a92257..6373ccd 100644
--- a/content/renderer/media/android/audio_decoder_android.cc
+++ b/content/renderer/media/android/audio_decoder_android.cc
@@ -481,6 +481,9 @@
                               file_sample_rate);
 
   for (size_t m = 0; m < number_of_samples; m += number_of_channels) {
+    if (decoded_frames >= number_of_frames)
+      break;
+
     for (size_t k = 0; k < number_of_channels; ++k) {
       int16_t sample = decoded_samples[m + k];
       destination_bus->channelData(k)[decoded_frames] =
diff --git a/content/renderer/npapi/webplugin_impl.cc b/content/renderer/npapi/webplugin_impl.cc
index c611daa..ac739b5 100644
--- a/content/renderer/npapi/webplugin_impl.cc
+++ b/content/renderer/npapi/webplugin_impl.cc
@@ -258,8 +258,12 @@
     blink::WebPlugin* replacement_plugin =
         GetContentClient()->renderer()->CreatePluginReplacement(
             render_frame_, file_path_);
-    if (!replacement_plugin)
+    if (!replacement_plugin) {
+      // Maintain invariant that container() returns null when initialize()
+      // returns false.
+      SetContainer(nullptr);
       return false;
+    }
 
     // Disable scripting by this plugin before replacing it with the new
     // one. This plugin also needs destroying, so use destroy(), which will
diff --git a/content/renderer/pepper/pepper_webplugin_impl.cc b/content/renderer/pepper/pepper_webplugin_impl.cc
index b96bd0c..2773194 100644
--- a/content/renderer/pepper/pepper_webplugin_impl.cc
+++ b/content/renderer/pepper/pepper_webplugin_impl.cc
@@ -124,14 +124,22 @@
     blink::WebPlugin* replacement_plugin =
         GetContentClient()->renderer()->CreatePluginReplacement(
             init_data_->render_frame, init_data_->module->path());
-    if (!replacement_plugin || !replacement_plugin->initialize(container))
+    if (!replacement_plugin)
       return false;
 
     container->setPlugin(replacement_plugin);
+    if (!replacement_plugin->initialize(container)) {
+      CHECK(replacement_plugin->container() == nullptr);
+      return false;
+    }
+
+    CHECK(container->plugin() == replacement_plugin);
+    CHECK(replacement_plugin->container() == container);
     return true;
   }
 
   init_data_.reset();
+  CHECK(container->plugin() == this);
   container_ = container;
   return true;
 }
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index c768e6ae..ace7f67 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1276,6 +1276,11 @@
   if (main_frame && main_frame->isWebLocalFrame())
     GetContentClient()->SetActiveURL(main_frame->document().url());
 
+  // Input IPC messages must not be processed if the RenderView is in
+  // swapped out state.
+  if (is_swapped_out_ && IPC_MESSAGE_ID_CLASS(message.type()) == InputMsgStart)
+    return false;
+
   base::ObserverListBase<RenderViewObserver>::Iterator it(&observers_);
   RenderViewObserver* observer;
   while ((observer = it.GetNext()) != NULL)
@@ -3066,6 +3071,9 @@
 }
 
 void RenderViewImpl::OnSetFocus(bool enable) {
+  // This message must always be received when the main frame is a
+  // WebLocalFrame.
+  CHECK(webview()->mainFrame()->isWebLocalFrame());
   RenderWidget::OnSetFocus(enable);
 
 #if defined(ENABLE_PLUGINS)
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 1d4293da..2a9ad59d 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -1045,8 +1045,7 @@
 }
 
 void RenderWidget::OnHandleInputEvent(const blink::WebInputEvent* input_event,
-                                      const ui::LatencyInfo& latency_info,
-                                      bool is_keyboard_shortcut) {
+                                      const ui::LatencyInfo& latency_info) {
   if (!input_event)
     return;
   base::AutoReset<bool> handling_input_event_resetter(&handling_input_event_,
@@ -1158,6 +1157,9 @@
   // If this RawKeyDown event corresponds to a browser keyboard shortcut and
   // it's not processed by webkit, then we need to suppress the upcoming Char
   // events.
+  bool is_keyboard_shortcut =
+      input_event->type == WebInputEvent::RawKeyDown &&
+      static_cast<const WebKeyboardEvent*>(input_event)->isBrowserShortcut;
   if (!processed && is_keyboard_shortcut)
     suppress_next_char_events_ = true;
 
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 608e904..eac8544 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -410,8 +410,7 @@
 
   // RenderWidget IPC message handlers
   void OnHandleInputEvent(const blink::WebInputEvent* event,
-                          const ui::LatencyInfo& latency_info,
-                          bool keyboard_shortcut);
+                          const ui::LatencyInfo& latency_info);
   void OnCursorVisibilityChange(bool is_visible);
   void OnMouseCaptureLost();
   virtual void OnSetFocus(bool enable);
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index 9211acac..e4319f5 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -34,7 +34,7 @@
   }
 
   void SendInputEvent(const blink::WebInputEvent& event) {
-    OnHandleInputEvent(&event, ui::LatencyInfo(), false);
+    OnHandleInputEvent(&event, ui::LatencyInfo());
   }
 
   void set_always_overscroll(bool overscroll) {
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 16c5d7f..c3f9fb81 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -149,8 +149,6 @@
     "renderer/layout_test/blink_test_helpers.h",
     "renderer/layout_test/blink_test_runner.cc",
     "renderer/layout_test/blink_test_runner.h",
-    "renderer/layout_test/gc_controller.cc",
-    "renderer/layout_test/gc_controller.h",
     "renderer/layout_test/layout_test_content_renderer_client.cc",
     "renderer/layout_test/layout_test_content_renderer_client.h",
     "renderer/layout_test/layout_test_render_frame_observer.cc",
diff --git a/content/shell/renderer/layout_test/blink_test_runner.cc b/content/shell/renderer/layout_test/blink_test_runner.cc
index 726a220..45f129e 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.cc
+++ b/content/shell/renderer/layout_test/blink_test_runner.cc
@@ -45,7 +45,6 @@
 #include "content/shell/common/shell_messages.h"
 #include "content/shell/common/shell_switches.h"
 #include "content/shell/renderer/layout_test/blink_test_helpers.h"
-#include "content/shell/renderer/layout_test/gc_controller.h"
 #include "content/shell/renderer/layout_test/layout_test_render_process_observer.h"
 #include "content/shell/renderer/layout_test/leak_detector.h"
 #include "net/base/filename_util.h"
@@ -764,7 +763,6 @@
   WebTestingSupport::injectInternalsObject(frame);
   LayoutTestRenderProcessObserver::GetInstance()->test_interfaces()->BindTo(
       frame);
-  GCController::Install(frame);
 }
 
 bool BlinkTestRunner::OnMessageReceived(const IPC::Message& message) {
diff --git a/crypto/ec_private_key.h b/crypto/ec_private_key.h
index 87af8389..a3ba49d 100644
--- a/crypto/ec_private_key.h
+++ b/crypto/ec_private_key.h
@@ -34,9 +34,6 @@
  public:
   ~ECPrivateKey();
 
-  // Returns whether the system supports elliptic curve cryptography.
-  static bool IsSupported();
-
   // Creates a new random instance. Can return NULL if initialization fails.
   // The created key will use the NIST P-256 curve.
   // TODO(mattm): Add a curve parameter.
diff --git a/crypto/ec_private_key_nss.cc b/crypto/ec_private_key_nss.cc
index 5092010c..5f8a4e6 100644
--- a/crypto/ec_private_key_nss.cc
+++ b/crypto/ec_private_key_nss.cc
@@ -15,7 +15,6 @@
 #include <pk11pub.h>
 #include <secmod.h>
 
-#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "crypto/nss_util.h"
@@ -25,34 +24,6 @@
 
 namespace {
 
-PK11SlotInfo* GetTempKeySlot() {
-  return PK11_GetInternalSlot();
-}
-
-class EllipticCurveSupportChecker {
- public:
-  EllipticCurveSupportChecker() {
-    // NOTE: we can do this check here only because we use the NSS internal
-    // slot.  If we support other slots in the future, checking whether they
-    // support ECDSA may block NSS, and the value may also change as devices are
-    // inserted/removed, so we would need to re-check on every use.
-    crypto::EnsureNSSInit();
-    crypto::ScopedPK11Slot slot(GetTempKeySlot());
-    supported_ = PK11_DoesMechanism(slot.get(), CKM_EC_KEY_PAIR_GEN) &&
-        PK11_DoesMechanism(slot.get(), CKM_ECDSA);
-  }
-
-  bool Supported() {
-    return supported_;
-  }
-
- private:
-  bool supported_;
-};
-
-static base::LazyInstance<EllipticCurveSupportChecker>::Leaky
-    g_elliptic_curve_supported = LAZY_INSTANCE_INITIALIZER;
-
 // Copied from rsa_private_key_nss.cc.
 static bool ReadAttribute(SECKEYPrivateKey* key,
                           CK_ATTRIBUTE_TYPE type,
@@ -82,15 +53,10 @@
 }
 
 // static
-bool ECPrivateKey::IsSupported() {
-  return g_elliptic_curve_supported.Get().Supported();
-}
-
-// static
 ECPrivateKey* ECPrivateKey::Create() {
   EnsureNSSInit();
 
-  ScopedPK11Slot slot(GetTempKeySlot());
+  ScopedPK11Slot slot(PK11_GetInternalSlot());
   if (!slot)
     return nullptr;
 
@@ -140,7 +106,7 @@
     const std::vector<uint8>& subject_public_key_info) {
   EnsureNSSInit();
 
-  ScopedPK11Slot slot(GetTempKeySlot());
+  ScopedPK11Slot slot(PK11_GetInternalSlot());
   if (!slot)
     return nullptr;
 
diff --git a/crypto/ec_private_key_openssl.cc b/crypto/ec_private_key_openssl.cc
index 1a06028..9836fa6 100644
--- a/crypto/ec_private_key_openssl.cc
+++ b/crypto/ec_private_key_openssl.cc
@@ -93,9 +93,6 @@
 }
 
 // static
-bool ECPrivateKey::IsSupported() { return true; }
-
-// static
 ECPrivateKey* ECPrivateKey::Create() {
   OpenSSLErrStackTracer err_tracer(FROM_HERE);
 
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 6c8277a..32adecc 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -41,6 +41,7 @@
     "bluetooth/bluetooth_device_win_unittest.cc",
     "bluetooth/bluetooth_discovery_filter_unittest.cc",
     "bluetooth/bluetooth_gatt_chromeos_unittest.cc",
+    "bluetooth/bluetooth_gatt_service_unittest.cc",
     "bluetooth/bluetooth_low_energy_win_unittest.cc",
     "bluetooth/bluetooth_service_record_win_unittest.cc",
     "bluetooth/bluetooth_socket_chromeos_unittest.cc",
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn
index 2cb34170..a5ea564 100644
--- a/device/bluetooth/BUILD.gn
+++ b/device/bluetooth/BUILD.gn
@@ -200,6 +200,7 @@
   java_sources_needing_jni = [
     "android/java/src/org/chromium/device/bluetooth/ChromeBluetoothAdapter.java",
     "android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java",
+    "android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java",
     "android/java/src/org/chromium/device/bluetooth/Wrappers.java",
   ]
 
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
index 037cd95..c55fb45 100644
--- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
+++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
@@ -163,8 +163,12 @@
                     if (mNativeBluetoothDeviceAndroid != 0) {
                         for (Wrappers.BluetoothGattServiceWrapper service :
                                 mBluetoothGatt.getServices()) {
-                            nativeCreateGattRemoteService(mNativeBluetoothDeviceAndroid,
-                                    service.getInstanceId(), service);
+                            // Create a device unique service ID. getInstanceId only differs
+                            // between service instances with the same UUID.
+                            String serviceInstanceId =
+                                    service.getUuid().toString() + service.getInstanceId();
+                            nativeCreateGattRemoteService(
+                                    mNativeBluetoothDeviceAndroid, serviceInstanceId, service);
                         }
                     }
                 }
@@ -183,6 +187,6 @@
     // 'Object' type must be used for |bluetoothGattServiceWrapper| because inner class
     // Wrappers.BluetoothGattServiceWrapper reference is not handled by jni_generator.py JavaToJni.
     // http://crbug.com/505554
-    private native void nativeCreateGattRemoteService(
-            long nativeBluetoothDeviceAndroid, int instanceId, Object bluetoothGattServiceWrapper);
+    private native void nativeCreateGattRemoteService(long nativeBluetoothDeviceAndroid,
+            String instanceId, Object bluetoothGattServiceWrapper);
 }
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java
new file mode 100644
index 0000000..62c379a
--- /dev/null
+++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java
@@ -0,0 +1,46 @@
+// 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.device.bluetooth;
+
+import org.chromium.base.Log;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+/**
+ * Exposes android.bluetooth.BluetoothGattService as necessary
+ * for C++ device::BluetoothRemoteGattServiceAndroid.
+ *
+ * Lifetime is controlled by
+ * device::BluetoothRemoteGattServiceAndroid.
+ */
+@JNINamespace("device")
+final class ChromeBluetoothRemoteGattService {
+    private static final String TAG = "Bluetooth";
+
+    final Wrappers.BluetoothGattServiceWrapper mService;
+
+    private ChromeBluetoothRemoteGattService(Wrappers.BluetoothGattServiceWrapper serviceWrapper) {
+        mService = serviceWrapper;
+        Log.v(TAG, "ChromeBluetoothRemoteGattService created.");
+    }
+
+    // ---------------------------------------------------------------------------------------------
+    // BluetoothRemoteGattServiceAndroid methods implemented in java:
+
+    // Implements BluetoothRemoteGattServiceAndroid::Create.
+    // 'Object' type must be used because inner class Wrappers.BluetoothGattServiceWrapper reference
+    // is not handled by jni_generator.py JavaToJni. http://crbug.com/505554
+    @CalledByNative
+    private static ChromeBluetoothRemoteGattService create(Object serviceWrapper) {
+        return new ChromeBluetoothRemoteGattService(
+                (Wrappers.BluetoothGattServiceWrapper) serviceWrapper);
+    }
+
+    // Implements BluetoothRemoteGattServiceAndroid::GetUUID.
+    @CalledByNative
+    private String getUUID() {
+        return mService.getUuid().toString();
+    }
+}
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java
index df54ee8..9f4d35fb 100644
--- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java
+++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java
@@ -28,6 +28,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.UUID;
 
 /**
  * Wrapper classes around android.bluetooth.* classes that provide an
@@ -333,5 +334,9 @@
         public int getInstanceId() {
             return mService.getInstanceId();
         }
+
+        public UUID getUuid() {
+            return mService.getUuid();
+        }
     }
 }
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp
index c197d942..f99d0176 100644
--- a/device/bluetooth/bluetooth.gyp
+++ b/device/bluetooth/bluetooth.gyp
@@ -256,6 +256,7 @@
           'sources': [
             'android/java/src/org/chromium/device/bluetooth/ChromeBluetoothAdapter.java',
             'android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java',
+            'android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java',
             'android/java/src/org/chromium/device/bluetooth/Wrappers.java',
           ],
           'variables': {
diff --git a/device/bluetooth/bluetooth_device_android.cc b/device/bluetooth/bluetooth_device_android.cc
index 1066ac4..fccd24fb 100644
--- a/device/bluetooth/bluetooth_device_android.cc
+++ b/device/bluetooth/bluetooth_device_android.cc
@@ -226,11 +226,12 @@
 void BluetoothDeviceAndroid::CreateGattRemoteService(
     JNIEnv* env,
     jobject caller,
-    int32_t instanceId,
+    const jstring& instanceId,
     jobject bluetooth_gatt_service_wrapper  // Java Type:
                                             // BluetoothGattServiceWrapper
     ) {
-  std::string instanceIdString = base::StringPrintf("%d", instanceId);
+  std::string instanceIdString =
+      base::android::ConvertJavaStringToUTF8(env, instanceId);
 
   if (gatt_services_.contains(instanceIdString))
     return;
diff --git a/device/bluetooth/bluetooth_device_android.h b/device/bluetooth/bluetooth_device_android.h
index e830e94..bed6780 100644
--- a/device/bluetooth/bluetooth_device_android.h
+++ b/device/bluetooth/bluetooth_device_android.h
@@ -99,7 +99,7 @@
   void CreateGattRemoteService(
       JNIEnv* env,
       jobject caller,
-      int32_t instanceId,
+      const jstring& instanceId,
       jobject bluetooth_gatt_service_wrapper);  // Java Type:
                                                 // BluetoothGattServiceWrapper
 
diff --git a/device/bluetooth/bluetooth_device_unittest.cc b/device/bluetooth/bluetooth_device_unittest.cc
index a89fc88..c6066ca 100644
--- a/device/bluetooth/bluetooth_device_unittest.cc
+++ b/device/bluetooth/bluetooth_device_unittest.cc
@@ -436,10 +436,13 @@
   SimulateGattConnection(device);
   EXPECT_EQ(1, gatt_discovery_attempts_);
 
-  // TODO(scheib): Add more control over how many services are created and
-  // their properties. http://crbug.com/541400
-  SimulateGattServicesDiscovered(device);
-  EXPECT_EQ(2u, device->GetGattServices().size());
+  std::vector<std::string> services;
+  services.push_back("00000000-0000-1000-8000-00805f9b34fb");
+  // 2 duplicate UUIDs creating 2 instances.
+  services.push_back("00000001-0000-1000-8000-00805f9b34fb");
+  services.push_back("00000001-0000-1000-8000-00805f9b34fb");
+  SimulateGattServicesDiscovered(device, services);
+  EXPECT_EQ(3u, device->GetGattServices().size());
 }
 #endif  // defined(OS_ANDROID)
 
diff --git a/device/bluetooth/bluetooth_gatt_service_unittest.cc b/device/bluetooth/bluetooth_gatt_service_unittest.cc
new file mode 100644
index 0000000..91fd214
--- /dev/null
+++ b/device/bluetooth/bluetooth_gatt_service_unittest.cc
@@ -0,0 +1,45 @@
+// 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 "device/bluetooth/bluetooth_gatt_service.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_ANDROID)
+#include "device/bluetooth/test/bluetooth_test_android.h"
+#elif defined(OS_MACOSX)
+#include "device/bluetooth/test/bluetooth_test_mac.h"
+#endif
+
+namespace device {
+
+#if defined(OS_ANDROID)
+TEST_F(BluetoothTest, GetUUIDAndGetIdentifier) {
+  InitWithFakeAdapter();
+  StartDiscoverySession();
+  BluetoothDevice* device = DiscoverLowEnergyDevice(3);
+  device->CreateGattConnection(GetGattConnectionCallback(),
+                               GetConnectErrorCallback());
+  ResetEventCounts();
+  SimulateGattConnection(device);
+  EXPECT_EQ(1, gatt_discovery_attempts_);
+
+  // Create multiple instances with the same UUID.
+  BluetoothUUID uuid("00000000-0000-1000-8000-00805f9b34fb");
+  std::vector<std::string> services;
+  services.push_back(uuid.canonical_value());
+  services.push_back(uuid.canonical_value());
+  SimulateGattServicesDiscovered(device, services);
+
+  // Each has the same UUID.
+  EXPECT_EQ(uuid, device->GetGattServices()[0]->GetUUID());
+  EXPECT_EQ(uuid, device->GetGattServices()[1]->GetUUID());
+
+  // Instance IDs are unique.
+  EXPECT_NE(device->GetGattServices()[0]->GetIdentifier(),
+            device->GetGattServices()[1]->GetIdentifier());
+}
+#endif  // defined(OS_ANDROID)
+
+}  // namespace device
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_android.cc b/device/bluetooth/bluetooth_remote_gatt_service_android.cc
index aa25fec..c9caa3a3 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_android.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_service_android.cc
@@ -4,8 +4,13 @@
 
 #include "device/bluetooth/bluetooth_remote_gatt_service_android.h"
 
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
 #include "device/bluetooth/bluetooth_adapter_android.h"
 #include "device/bluetooth/bluetooth_device_android.h"
+#include "jni/ChromeBluetoothRemoteGattService_jni.h"
+
+using base::android::AttachCurrentThread;
 
 namespace device {
 
@@ -18,16 +23,26 @@
   BluetoothRemoteGattServiceAndroid* service =
       new BluetoothRemoteGattServiceAndroid(adapter, device, instanceId);
 
+  service->j_service_.Reset(Java_ChromeBluetoothRemoteGattService_create(
+      AttachCurrentThread(), bluetooth_remote_gatt_service_wrapper));
+
   return service;
 }
 
+// static
+bool BluetoothRemoteGattServiceAndroid::RegisterJNI(JNIEnv* env) {
+  return RegisterNativesImpl(
+      env);  // Generated in ChromeBluetoothRemoteGattService_jni.h
+}
+
 std::string BluetoothRemoteGattServiceAndroid::GetIdentifier() const {
   return instanceId_;
 }
 
 device::BluetoothUUID BluetoothRemoteGattServiceAndroid::GetUUID() const {
-  NOTIMPLEMENTED();
-  return device::BluetoothUUID();
+  return device::BluetoothUUID(
+      ConvertJavaStringToUTF8(Java_ChromeBluetoothRemoteGattService_getUUID(
+          AttachCurrentThread(), j_service_.obj())));
 }
 
 bool BluetoothRemoteGattServiceAndroid::IsLocal() const {
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_android.h b/device/bluetooth/bluetooth_remote_gatt_service_android.h
index 6e0e702..5bc9e3d 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_android.h
+++ b/device/bluetooth/bluetooth_remote_gatt_service_android.h
@@ -41,6 +41,9 @@
       // BluetoothRemoteGattServiceWrapper
       std::string instanceId);
 
+  // Register C++ methods exposed to Java using JNI.
+  static bool RegisterJNI(JNIEnv* env);
+
   // device::BluetoothGattService overrides.
   std::string GetIdentifier() const override;
   device::BluetoothUUID GetUUID() const override;
@@ -69,6 +72,9 @@
                                     std::string instanceId);
   ~BluetoothRemoteGattServiceAndroid() override;
 
+  // Java object org.chromium.device.bluetooth.ChromeBluetoothRemoteGattService.
+  base::android::ScopedJavaGlobalRef<jobject> j_service_;
+
   // The adapter associated with this service. It's ok to store a raw pointer
   // here since |adapter_| indirectly owns this instance.
   BluetoothAdapterAndroid* adapter_;
diff --git a/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java b/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
index 062c3c8..2499c7b 100644
--- a/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
+++ b/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
@@ -17,7 +17,9 @@
 import org.chromium.base.annotations.JNINamespace;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.UUID;
 
 /**
  * Fake implementations of android.bluetooth.* classes for testing.
@@ -212,15 +214,20 @@
         // Create a call to onServicesDiscovered on the |chrome_device| using parameter
         // |status|.
         @CalledByNative("FakeBluetoothDevice")
-        private static void servicesDiscovered(ChromeBluetoothDevice chromeDevice, int status) {
+        private static void servicesDiscovered(
+                ChromeBluetoothDevice chromeDevice, int status, String uuidsSpaceDelimited) {
             FakeBluetoothDevice fakeDevice = (FakeBluetoothDevice) chromeDevice.mDevice;
 
-            // TODO(scheib): Add more control over how many services are created and
-            // their properties. http://crbug.com/541400
             if (status == android.bluetooth.BluetoothGatt.GATT_SUCCESS) {
                 fakeDevice.mGatt.mServices.clear();
-                fakeDevice.mGatt.mServices.add(new FakeBluetoothGattService(0));
-                fakeDevice.mGatt.mServices.add(new FakeBluetoothGattService(1));
+                HashMap<String, Integer> uuidsToInstanceIdMap = new HashMap<String, Integer>();
+                for (String uuid : uuidsSpaceDelimited.split(" ")) {
+                    Integer previousId = uuidsToInstanceIdMap.get(uuid);
+                    int instanceId = (previousId == null) ? 0 : previousId + 1;
+                    uuidsToInstanceIdMap.put(uuid, instanceId);
+                    fakeDevice.mGatt.mServices.add(
+                            new FakeBluetoothGattService(UUID.fromString(uuid), instanceId));
+                }
             }
 
             fakeDevice.mGattCallback.onServicesDiscovered(status);
@@ -297,9 +304,11 @@
      */
     static class FakeBluetoothGattService extends Wrappers.BluetoothGattServiceWrapper {
         final int mInstanceId;
+        final UUID mUuid;
 
-        public FakeBluetoothGattService(int instanceId) {
+        public FakeBluetoothGattService(UUID uuid, int instanceId) {
             super(null);
+            mUuid = uuid;
             mInstanceId = instanceId;
         }
 
@@ -307,6 +316,11 @@
         public int getInstanceId() {
             return mInstanceId;
         }
+
+        @Override
+        public UUID getUuid() {
+            return mUuid;
+        }
     }
 
     // ---------------------------------------------------------------------------------------------
diff --git a/device/bluetooth/test/bluetooth_test.h b/device/bluetooth/test/bluetooth_test.h
index 43b47f2..11e6b6b 100644
--- a/device/bluetooth/test/bluetooth_test.h
+++ b/device/bluetooth/test/bluetooth_test.h
@@ -84,10 +84,12 @@
   // Simulates GattConnection disconnecting.
   virtual void SimulateGattDisconnection(BluetoothDevice* device) {}
 
-  // Simulates success of discovering services. Two services are created.
-  // TODO(scheib): Add more control over how many services are created and
-  // their properties. http://crbug.com/541400
-  virtual void SimulateGattServicesDiscovered(BluetoothDevice* device) {}
+  // Simulates success of discovering services. |uuids| is used to create a
+  // service for each UUID string. Multiple UUIDs with the same value produce
+  // multiple service instances.
+  virtual void SimulateGattServicesDiscovered(
+      BluetoothDevice* device,
+      const std::vector<std::string>& uuids) {}
 
   // Simulates failure to discover services.
   virtual void SimulateGattServicesDiscoveryError(BluetoothDevice* device) {}
diff --git a/device/bluetooth/test/bluetooth_test_android.cc b/device/bluetooth/test/bluetooth_test_android.cc
index 01bc12f..48c2ab2 100644
--- a/device/bluetooth/test/bluetooth_test_android.cc
+++ b/device/bluetooth/test/bluetooth_test_android.cc
@@ -4,6 +4,10 @@
 
 #include "device/bluetooth/test/bluetooth_test_android.h"
 
+#include <iterator>
+#include <sstream>
+
+#include "base/android/jni_string.h"
 #include "base/logging.h"
 #include "device/bluetooth/android/wrappers.h"
 #include "device/bluetooth/bluetooth_adapter_android.h"
@@ -107,13 +111,22 @@
 }
 
 void BluetoothTestAndroid::SimulateGattServicesDiscovered(
-    BluetoothDevice* device) {
+    BluetoothDevice* device,
+    const std::vector<std::string>& uuids) {
   BluetoothDeviceAndroid* device_android =
       static_cast<BluetoothDeviceAndroid*>(device);
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  // Join UUID strings into a single string.
+  std::ostringstream uuids_space_delimited;
+  std::copy(uuids.begin(), uuids.end(),
+            std::ostream_iterator<std::string>(uuids_space_delimited, " "));
 
   Java_FakeBluetoothDevice_servicesDiscovered(
-      AttachCurrentThread(), device_android->GetJavaObject().obj(),
-      0);  // android.bluetooth.BluetoothGatt.GATT_SUCCESS
+      env, device_android->GetJavaObject().obj(),
+      0,  // android.bluetooth.BluetoothGatt.GATT_SUCCESS
+      base::android::ConvertUTF8ToJavaString(env, uuids_space_delimited.str())
+          .obj());
 }
 
 void BluetoothTestAndroid::SimulateGattServicesDiscoveryError(
@@ -123,7 +136,8 @@
 
   Java_FakeBluetoothDevice_servicesDiscovered(
       AttachCurrentThread(), device_android->GetJavaObject().obj(),
-      0x00000101);  // android.bluetooth.BluetoothGatt.GATT_FAILURE
+      0x00000101,  // android.bluetooth.BluetoothGatt.GATT_FAILURE
+      nullptr);
 }
 
 void BluetoothTestAndroid::OnFakeBluetoothDeviceConnectGattCalled(
diff --git a/device/bluetooth/test/bluetooth_test_android.h b/device/bluetooth/test/bluetooth_test_android.h
index 4db263b..306d81a 100644
--- a/device/bluetooth/test/bluetooth_test_android.h
+++ b/device/bluetooth/test/bluetooth_test_android.h
@@ -31,7 +31,9 @@
   void SimulateGattConnectionError(BluetoothDevice* device,
                                    BluetoothDevice::ConnectErrorCode) override;
   void SimulateGattDisconnection(BluetoothDevice* device) override;
-  void SimulateGattServicesDiscovered(BluetoothDevice* device) override;
+  void SimulateGattServicesDiscovered(
+      BluetoothDevice* device,
+      const std::vector<std::string>& uuids) override;
   void SimulateGattServicesDiscoveryError(BluetoothDevice* device) override;
 
   // Records that Java FakeBluetoothDevice connectGatt was called.
diff --git a/device/core/BUILD.gn b/device/core/BUILD.gn
index d931807..e85acb6 100644
--- a/device/core/BUILD.gn
+++ b/device/core/BUILD.gn
@@ -2,7 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-source_set("core") {
+component("core") {
+  output_name = "device_core"
+
   sources = [
     "device_client.cc",
     "device_client.h",
@@ -10,6 +12,8 @@
     "device_monitor_win.h",
   ]
 
+  defines = [ "DEVICE_CORE_IMPLEMENTATION" ]
+
   public_deps = [
     "//base",
   ]
diff --git a/device/core/core.gyp b/device/core/core.gyp
index 034b9e359..d27073d 100644
--- a/device/core/core.gyp
+++ b/device/core/core.gyp
@@ -9,10 +9,13 @@
   'targets': [
     {
       'target_name': 'device_core',
-      'type': 'static_library',
+      'type': '<(component)',
       'include_dirs': [
         '../..',
       ],
+      'defines': [
+        'DEVICE_CORE_IMPLEMENTATION',
+      ],
       'sources': [
         'device_client.cc',
         'device_client.h',
@@ -20,8 +23,8 @@
         'device_monitor_win.h',
       ],
       'dependencies': [
-        '<(DEPTH)/third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
-      ],
+        '../../base/base.gyp:base',
+      ]
     },
   ],
 }
diff --git a/device/core/device_client.h b/device/core/device_client.h
index d63471b..9fdc7f1 100644
--- a/device/core/device_client.h
+++ b/device/core/device_client.h
@@ -6,20 +6,17 @@
 #define DEVICE_CORE_DEVICE_CLIENT_H_
 
 #include "base/macros.h"
+#include "device/core/device_core_export.h"
 
 namespace device {
 
 class HidService;
 class UsbService;
 
-namespace usb {
-class DeviceManager;
-}
-
 // Interface used by consumers of //device APIs to get pointers to the service
 // singletons appropriate for a given embedding application. For an example see
 // //chrome/browser/chrome_device_client.h.
-class DeviceClient {
+class DEVICE_CORE_EXPORT DeviceClient {
  public:
   // Construction sets the single instance.
   DeviceClient();
diff --git a/device/core/device_core_export.h b/device/core/device_core_export.h
new file mode 100644
index 0000000..6f1cddb
--- /dev/null
+++ b/device/core/device_core_export.h
@@ -0,0 +1,28 @@
+// 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 DEVICE_CORE_DEVICE_CORE_EXPORT_H_
+#define DEVICE_CORE_DEVICE_CORE_EXPORT_H_
+
+#if defined(COMPONENT_BUILD) && defined(WIN32)
+
+#if defined(DEVICE_CORE_IMPLEMENTATION)
+#define DEVICE_CORE_EXPORT __declspec(dllexport)
+#else
+#define DEVICE_CORE_EXPORT __declspec(dllimport)
+#endif
+
+#elif defined(COMPONENT_BUILD) && !defined(WIN32)
+
+#if defined(DEVICE_CORE_IMPLEMENTATION)
+#define DEVICE_CORE_EXPORT __attribute__((visibility("default")))
+#else
+#define DEVICE_CORE_EXPORT
+#endif
+
+#else
+#define DEVICE_CORE_EXPORT
+#endif
+
+#endif  // DEVICE_CORE_DEVICE_CORE_EXPORT_H_
diff --git a/device/core/device_monitor_win.h b/device/core/device_monitor_win.h
index e8becd7..36600e4 100644
--- a/device/core/device_monitor_win.h
+++ b/device/core/device_monitor_win.h
@@ -8,14 +8,15 @@
 #include <windows.h>
 
 #include "base/observer_list.h"
+#include "device/core/device_core_export.h"
 
 namespace device {
 
 // Use an instance of this class to observe devices being added and removed
 // from the system, matched by device interface GUID.
-class DeviceMonitorWin {
+class DEVICE_CORE_EXPORT DeviceMonitorWin {
  public:
-  class Observer {
+  class DEVICE_CORE_EXPORT Observer {
    public:
     virtual void OnDeviceAdded(const GUID& class_guid,
                                const std::string& device_path);
diff --git a/device/device_tests.gyp b/device/device_tests.gyp
index a645670..3cc4fc0 100644
--- a/device/device_tests.gyp
+++ b/device/device_tests.gyp
@@ -47,6 +47,7 @@
         'bluetooth/bluetooth_device_win_unittest.cc',
         'bluetooth/bluetooth_discovery_filter_unittest.cc',
         'bluetooth/bluetooth_gatt_chromeos_unittest.cc',
+        'bluetooth/bluetooth_gatt_service_unittest.cc',
         'bluetooth/bluetooth_low_energy_win_unittest.cc',
         'bluetooth/bluetooth_service_record_win_unittest.cc',
         'bluetooth/bluetooth_socket_chromeos_unittest.cc',
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 9c9424e..3fe0d25 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -18,6 +18,8 @@
     "//components/pref_registry",
     "//components/sessions",
     "//components/ui/zoom",
+    "//components/update_client",
+    "//components/version_info",
     "//components/web_cache/browser",
     "//components/web_modal",
     "//content/public/browser",
diff --git a/extensions/browser/extension_system.h b/extensions/browser/extension_system.h
index c6d2e09..7758051d 100644
--- a/extensions/browser/extension_system.h
+++ b/extensions/browser/extension_system.h
@@ -122,6 +122,13 @@
   // so it can be retrieved from ExtensionSystem directly.
   virtual scoped_ptr<ExtensionSet> GetDependentExtensions(
       const Extension* extension) = 0;
+
+  // Install an updated version of |extension_id| with the version given in
+  // temp_dir. Ownership of |temp_dir| in the filesystem is transferred and
+  // implementors of this function are responsible for cleaning it up on
+  // errors, etc.
+  virtual void InstallUpdate(const std::string& extension_id,
+                             const base::FilePath& temp_dir) = 0;
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/extensions_browser_client.cc b/extensions/browser/extensions_browser_client.cc
index 495ac50..d113f11 100644
--- a/extensions/browser/extensions_browser_client.cc
+++ b/extensions/browser/extensions_browser_client.cc
@@ -6,7 +6,9 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
+#include "components/update_client/update_client.h"
 #include "extensions/browser/extension_error.h"
+#include "extensions/browser/updater/update_client_config.h"
 
 namespace extensions {
 
@@ -16,6 +18,11 @@
 
 }  // namespace
 
+scoped_refptr<update_client::UpdateClient>
+ExtensionsBrowserClient::CreateUpdateClient(content::BrowserContext* context) {
+  return scoped_refptr<update_client::UpdateClient>(nullptr);
+}
+
 void ExtensionsBrowserClient::ReportError(content::BrowserContext* context,
                                           scoped_ptr<ExtensionError> error) {
   LOG(ERROR) << error->GetDebugString();
diff --git a/extensions/browser/extensions_browser_client.h b/extensions/browser/extensions_browser_client.h
index 89763d9d..a5ddd86 100644
--- a/extensions/browser/extensions_browser_client.h
+++ b/extensions/browser/extensions_browser_client.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "extensions/browser/extension_event_histogram_value.h"
 #include "extensions/browser/extension_prefs_observer.h"
@@ -35,6 +36,10 @@
 class URLRequestJob;
 }
 
+namespace update_client {
+class UpdateClient;
+}
+
 namespace extensions {
 
 class ApiActivityMonitor;
@@ -236,6 +241,10 @@
   virtual void AttachExtensionTaskManagerTag(content::WebContents* web_contents,
                                              ViewType view_type) {}
 
+  // Returns a new UpdateClient.
+  virtual scoped_refptr<update_client::UpdateClient> CreateUpdateClient(
+      content::BrowserContext* context);
+
   // Returns the single instance of |this|.
   static ExtensionsBrowserClient* Get();
 
diff --git a/extensions/browser/mock_extension_system.cc b/extensions/browser/mock_extension_system.cc
index 00e3fc22..efcc546 100644
--- a/extensions/browser/mock_extension_system.cc
+++ b/extensions/browser/mock_extension_system.cc
@@ -71,4 +71,9 @@
   return scoped_ptr<ExtensionSet>();
 }
 
+void MockExtensionSystem::InstallUpdate(const std::string& extension_id,
+                                        const base::FilePath& temp_dir) {
+  NOTREACHED();
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/mock_extension_system.h b/extensions/browser/mock_extension_system.h
index af847f5..b055b42 100644
--- a/extensions/browser/mock_extension_system.h
+++ b/extensions/browser/mock_extension_system.h
@@ -41,6 +41,8 @@
   ContentVerifier* content_verifier() override;
   scoped_ptr<ExtensionSet> GetDependentExtensions(
       const Extension* extension) override;
+  void InstallUpdate(const std::string& extension_id,
+                     const base::FilePath& temp_dir) override;
 
  private:
   content::BrowserContext* browser_context_;
diff --git a/extensions/browser/test_extensions_browser_client.cc b/extensions/browser/test_extensions_browser_client.cc
index d98f7af..da5ef277c 100644
--- a/extensions/browser/test_extensions_browser_client.cc
+++ b/extensions/browser/test_extensions_browser_client.cc
@@ -27,6 +27,11 @@
 
 TestExtensionsBrowserClient::~TestExtensionsBrowserClient() {}
 
+void TestExtensionsBrowserClient::SetUpdateClientFactory(
+    const base::Callback<update_client::UpdateClient*(void)>& factory) {
+  update_client_factory_ = factory;
+}
+
 void TestExtensionsBrowserClient::SetIncognitoContext(BrowserContext* context) {
   // If a context is provided it must be off-the-record.
   DCHECK(!context || context->IsOffTheRecord());
@@ -204,4 +209,12 @@
   return nullptr;
 }
 
+scoped_refptr<update_client::UpdateClient>
+TestExtensionsBrowserClient::CreateUpdateClient(
+    content::BrowserContext* context) {
+  return update_client_factory_.is_null()
+             ? nullptr
+             : make_scoped_refptr(update_client_factory_.Run());
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/test_extensions_browser_client.h b/extensions/browser/test_extensions_browser_client.h
index 274a8a9..be660e7 100644
--- a/extensions/browser/test_extensions_browser_client.h
+++ b/extensions/browser/test_extensions_browser_client.h
@@ -5,7 +5,13 @@
 #ifndef EXTENSIONS_BROWSER_TEST_EXTENSIONS_BROWSER_CLIENT_H_
 #define EXTENSIONS_BROWSER_TEST_EXTENSIONS_BROWSER_CLIENT_H_
 
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "components/update_client/update_client.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/updater/extension_cache.h"
 
@@ -30,6 +36,10 @@
     extension_cache_ = extension_cache.Pass();
   }
 
+  // Sets a factory to respond to calls of the CreateUpdateClient method.
+  void SetUpdateClientFactory(
+      const base::Callback<update_client::UpdateClient*(void)>& factory);
+
   // Associates an incognito context with |main_context_|.
   void SetIncognitoContext(content::BrowserContext* incognito_context);
 
@@ -97,6 +107,8 @@
   bool IsMinBrowserVersionSupported(const std::string& min_version) override;
   ExtensionWebContentsObserver* GetExtensionWebContentsObserver(
       content::WebContents* web_contents) override;
+  scoped_refptr<update_client::UpdateClient> CreateUpdateClient(
+      content::BrowserContext* context) override;
 
  private:
   content::BrowserContext* main_context_;       // Not owned.
@@ -110,6 +122,8 @@
 
   scoped_ptr<ExtensionCache> extension_cache_;
 
+  base::Callback<update_client::UpdateClient*(void)> update_client_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(TestExtensionsBrowserClient);
 };
 
diff --git a/extensions/browser/updater/update_client_config.cc b/extensions/browser/updater/update_client_config.cc
new file mode 100644
index 0000000..9f1d0d1
--- /dev/null
+++ b/extensions/browser/updater/update_client_config.cc
@@ -0,0 +1,29 @@
+// 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 "extensions/browser/updater/update_client_config.h"
+
+#include "content/public/browser/browser_thread.h"
+
+namespace extensions {
+
+UpdateClientConfig::UpdateClientConfig() {}
+
+scoped_refptr<base::SequencedTaskRunner>
+UpdateClientConfig::GetSequencedTaskRunner() const {
+  return content::BrowserThread::GetBlockingPool()
+      ->GetSequencedTaskRunnerWithShutdownBehavior(
+          content::BrowserThread::GetBlockingPool()->GetSequenceToken(),
+          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+UpdateClientConfig::GetSingleThreadTaskRunner() const {
+  return content::BrowserThread::GetMessageLoopProxyForThread(
+      content::BrowserThread::FILE);
+}
+
+UpdateClientConfig::~UpdateClientConfig() {}
+
+}  // namespace extensions
diff --git a/extensions/browser/updater/update_client_config.h b/extensions/browser/updater/update_client_config.h
new file mode 100644
index 0000000..32e7811f
--- /dev/null
+++ b/extensions/browser/updater/update_client_config.h
@@ -0,0 +1,40 @@
+// 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 EXTENSIONS_BROWSER_UPDATER_UPDATE_CLIENT_CONFIG_H_
+#define EXTENSIONS_BROWSER_UPDATER_UPDATE_CLIENT_CONFIG_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "components/update_client/configurator.h"
+
+namespace base {
+class SequencedTaskRunner;
+class SingleThreadTaskRunner;
+}
+
+namespace extensions {
+
+// Used to provide configuration settings to the UpdateClient.
+class UpdateClientConfig : public update_client::Configurator {
+ public:
+  UpdateClientConfig();
+
+  scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner()
+      const override;
+  scoped_refptr<base::SingleThreadTaskRunner> GetSingleThreadTaskRunner()
+      const override;
+
+ protected:
+  friend class base::RefCountedThreadSafe<UpdateClientConfig>;
+  ~UpdateClientConfig() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UpdateClientConfig);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_UPDATER_UPDATE_CLIENT_CONFIG_H_
diff --git a/extensions/browser/updater/update_data_provider.cc b/extensions/browser/updater/update_data_provider.cc
new file mode 100644
index 0000000..e0ad403d
--- /dev/null
+++ b/extensions/browser/updater/update_data_provider.cc
@@ -0,0 +1,72 @@
+// 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 "extensions/browser/updater/update_data_provider.h"
+
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "components/update_client/update_client.h"
+#include "content/public/browser/browser_thread.h"
+#include "crypto/sha2.h"
+#include "extensions/browser/content_verifier.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/updater/update_install_shim.h"
+#include "extensions/common/extension.h"
+
+namespace extensions {
+
+UpdateDataProvider::UpdateDataProvider(content::BrowserContext* context,
+                                       const InstallCallback& callback)
+    : context_(context), callback_(callback) {}
+
+UpdateDataProvider::~UpdateDataProvider() {}
+
+void UpdateDataProvider::Shutdown() {
+  context_ = nullptr;
+}
+
+void UpdateDataProvider::GetData(
+    const std::vector<std::string>& ids,
+    std::vector<update_client::CrxComponent>* data) {
+  if (!context_)
+    return;
+  const ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
+  for (const auto& id : ids) {
+    const Extension* extension = registry->GetInstalledExtension(id);
+    if (!extension)
+      continue;
+    data->push_back(update_client::CrxComponent());
+    update_client::CrxComponent* info = &data->back();
+    std::string pubkey_bytes;
+    base::Base64Decode(extension->public_key(), &pubkey_bytes);
+    info->pk_hash.resize(crypto::kSHA256Length, 0);
+    crypto::SHA256HashString(pubkey_bytes, vector_as_array(&info->pk_hash),
+                             info->pk_hash.size());
+    info->version = *extension->version();
+    info->allow_background_download = false;
+
+    info->installer = new UpdateInstallShim(
+        id, extension->path(),
+        base::Bind(&UpdateDataProvider::RunInstallCallback, this));
+  }
+}
+
+void UpdateDataProvider::RunInstallCallback(const std::string& extension_id,
+                                            const base::FilePath& temp_dir) {
+  if (!context_) {
+    content::BrowserThread::PostBlockingPoolTask(
+        FROM_HERE,
+        base::Bind(base::IgnoreResult(&base::DeleteFile), temp_dir, false));
+    return;
+  } else {
+    callback_.Run(context_, extension_id, temp_dir);
+  }
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/updater/update_data_provider.h b/extensions/browser/updater/update_data_provider.h
new file mode 100644
index 0000000..95cea59
--- /dev/null
+++ b/extensions/browser/updater/update_data_provider.h
@@ -0,0 +1,69 @@
+// 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 EXTENSIONS_BROWSER_UPDATER_UPDATE_DATA_PROVIDER_H_
+#define EXTENSIONS_BROWSER_UPDATER_UPDATE_DATA_PROVIDER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace content {
+class BrowserContext;
+}
+
+namespace update_client {
+struct CrxComponent;
+}
+
+namespace extensions {
+
+// This class exists to let an UpdateClient retrieve information about a set of
+// extensions it is doing an update check for.
+class UpdateDataProvider : public base::RefCounted<UpdateDataProvider> {
+ public:
+  typedef base::Callback<void(content::BrowserContext* context,
+                              const std::string& /* extension_id */,
+                              const base::FilePath& /* temp_dir */)>
+      InstallCallback;
+
+  // We need a browser context to use when retrieving data for a set of
+  // extension ids, as well as a callback for proceeding with installation
+  // steps once the UpdateClient has downloaded and unpacked an update for an
+  // extension.
+  UpdateDataProvider(content::BrowserContext* context,
+                     const InstallCallback& callback);
+
+  // Notify this object that the associated browser context is being shut down
+  // the pointer to the context should be dropped and no more work should be
+  // done.
+  void Shutdown();
+
+  // Matches update_client::UpdateClient::CrxDataCallback
+  void GetData(const std::vector<std::string>& ids,
+               std::vector<update_client::CrxComponent>* data);
+
+ private:
+  friend class base::RefCounted<UpdateDataProvider>;
+  ~UpdateDataProvider();
+
+  void RunInstallCallback(const std::string& extension_id,
+                          const base::FilePath& temp_dir);
+
+  content::BrowserContext* context_;
+  InstallCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(UpdateDataProvider);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_UPDATER_UPDATE_DATA_PROVIDER_H_
diff --git a/extensions/browser/updater/update_install_shim.cc b/extensions/browser/updater/update_install_shim.cc
new file mode 100644
index 0000000..4b6f5829
--- /dev/null
+++ b/extensions/browser/updater/update_install_shim.cc
@@ -0,0 +1,83 @@
+// 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 "extensions/browser/updater/update_install_shim.h"
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace extensions {
+
+UpdateInstallShim::UpdateInstallShim(std::string extension_id,
+                                     const base::FilePath& extension_root,
+                                     const UpdateInstallShimCallback& callback)
+    : extension_id_(extension_id),
+      extension_root_(extension_root),
+      callback_(callback) {}
+
+void UpdateInstallShim::OnUpdateError(int error) {
+  VLOG(1) << "OnUpdateError (" << extension_id_ << ") " << error;
+}
+
+bool UpdateInstallShim::Install(const base::DictionaryValue& manifest,
+                                const base::FilePath& unpack_path) {
+  base::ScopedTempDir temp_dir;
+  if (!temp_dir.CreateUniqueTempDir())
+    return false;
+
+  // The UpdateClient code will delete unpack_path if it still exists after
+  // this method is done, so we rename it on top of our temp dir.
+  if (!base::DeleteFile(temp_dir.path(), true) ||
+      !base::Move(unpack_path, temp_dir.path())) {
+    LOG(ERROR) << "Trying to install update for " << extension_id_
+               << "and failed to move " << unpack_path.value() << " to  "
+               << temp_dir.path().value();
+    return false;
+  }
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::Bind(&UpdateInstallShim::RunCallbackOnUIThread, this,
+                 temp_dir.Take()));
+  return true;
+}
+
+bool UpdateInstallShim::GetInstalledFile(const std::string& file,
+                                         base::FilePath* installed_file) {
+  base::FilePath relative_path = base::FilePath::FromUTF8Unsafe(file);
+  if (relative_path.IsAbsolute() || relative_path.ReferencesParent())
+    return false;
+  *installed_file = extension_root_.Append(relative_path);
+  if (!extension_root_.IsParent(*installed_file) ||
+      !base::PathExists(*installed_file)) {
+    VLOG(1) << "GetInstalledFile failed to find " << installed_file->value();
+    installed_file->clear();
+    return false;
+  }
+  return true;
+}
+
+bool UpdateInstallShim::Uninstall() {
+  NOTREACHED();
+  return false;
+}
+
+UpdateInstallShim::~UpdateInstallShim() {}
+
+void UpdateInstallShim::RunCallbackOnUIThread(const base::FilePath& temp_dir) {
+  if (callback_.is_null()) {
+    content::BrowserThread::PostBlockingPoolTask(
+        FROM_HERE, base::Bind(base::IgnoreResult(&base::DeleteFile), temp_dir,
+                              true /*recursive */));
+    return;
+  }
+  callback_.Run(extension_id_, temp_dir);
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/updater/update_install_shim.h b/extensions/browser/updater/update_install_shim.h
new file mode 100644
index 0000000..586e94e
--- /dev/null
+++ b/extensions/browser/updater/update_install_shim.h
@@ -0,0 +1,76 @@
+// 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 EXTENSIONS_BROWSER_UPDATER_UPDATE_INSTALL_SHIM_H_
+#define EXTENSIONS_BROWSER_UPDATER_UPDATE_INSTALL_SHIM_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "components/update_client/update_client.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace extensions {
+
+// A callback to implement the install of a new version of the extension.
+// Takes ownership of the directory at |temp_dir|.
+using UpdateInstallShimCallback =
+    base::Callback<void(const std::string& extension_id,
+                        const base::FilePath& temp_dir)>;
+
+// This class is used as a shim between the components::update_client and
+// extensions code, to help the generic update_client code prepare and then
+// install an updated version of an extension. Because the update_client code
+// doesn't have the notion of extension ids, we use instances of this class to
+// map an install request back to the original update check for a given
+// extension.
+class UpdateInstallShim : public update_client::CrxInstaller {
+ public:
+  // This method takes the id and root directory for an extension we're doing
+  // an update check for, as well as a callback to call if we get a new version
+  // of it to install.
+  UpdateInstallShim(std::string extension_id,
+                    const base::FilePath& extension_root,
+                    const UpdateInstallShimCallback& callback);
+
+  // Called when an update attempt failed.
+  void OnUpdateError(int error) override;
+
+  // This is called when a new version of an extension is unpacked at
+  // |unpack_path| and is ready for install.
+  bool Install(const base::DictionaryValue& manifest,
+               const base::FilePath& unpack_path) override;
+
+  // This is called by the generic differential update code in the
+  // update_client to provide the path to an existing file in the current
+  // version of the extension, so that it can be copied (or serve as the input
+  // to diff-patching) with output going to the directory with the new version
+  // being staged on disk for install.
+  bool GetInstalledFile(const std::string& file,
+                        base::FilePath* installed_file) override;
+
+  // This method is not relevant to extension updating.
+  bool Uninstall() override;
+
+ private:
+  friend class base::RefCountedThreadSafe<UpdateInstallShim>;
+  ~UpdateInstallShim() override;
+
+  // Takes ownership of the directory at path |temp_dir|.
+  void RunCallbackOnUIThread(const base::FilePath& temp_dir);
+
+  std::string extension_id_;
+  base::FilePath extension_root_;
+  UpdateInstallShimCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(UpdateInstallShim);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_UPDATER_UPDATE_INSTALL_SHIM_H_
diff --git a/extensions/browser/updater/update_service.cc b/extensions/browser/updater/update_service.cc
index 0cb055cf..ad40abd 100644
--- a/extensions/browser/updater/update_service.cc
+++ b/extensions/browser/updater/update_service.cc
@@ -4,16 +4,27 @@
 
 #include "extensions/browser/updater/update_service.h"
 
-#include <set>
-
-#include "base/message_loop/message_loop.h"
-#include "components/update_client/update_query_params.h"
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "components/update_client/update_client.h"
 #include "content/public/browser/browser_context.h"
-#include "extensions/browser/updater/extension_downloader.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/extensions_browser_client.h"
+#include "extensions/browser/updater/update_data_provider.h"
 #include "extensions/browser/updater/update_service_factory.h"
-#include "extensions/common/extension_urls.h"
 
-using update_client::UpdateQueryParams;
+namespace {
+
+void UpdateCheckCompleteCallback(int error) {}
+
+void InstallUpdateCallback(content::BrowserContext* context,
+                           const std::string& extension_id,
+                           const base::FilePath& temp_dir) {
+  extensions::ExtensionSystem::Get(context)
+      ->InstallUpdate(extension_id, temp_dir);
+}
+
+}  // namespace
 
 namespace extensions {
 
@@ -22,61 +33,32 @@
   return UpdateServiceFactory::GetForBrowserContext(context);
 }
 
-void UpdateService::DownloadAndInstall(
-    const std::string& id,
-    const base::Callback<void(bool)>& callback) {
-  DCHECK(download_callback_.is_null());
-  download_callback_ = callback;
-  downloader_->AddPendingExtension(id, extension_urls::GetWebstoreUpdateUrl(),
-                                   0);
-  downloader_->StartAllPending(nullptr);
+void UpdateService::Shutdown() {
+  if (update_data_provider_) {
+    update_data_provider_->Shutdown();
+    update_data_provider_ = nullptr;
+  }
+  update_client_ = nullptr;
+  context_ = nullptr;
 }
 
-UpdateService::UpdateService(content::BrowserContext* context)
-    : browser_context_(context),
-      downloader_(new ExtensionDownloader(this, context->GetRequestContext())) {
-  downloader_->set_manifest_query_params(
-      UpdateQueryParams::Get(UpdateQueryParams::CRX));
+void UpdateService::StartUpdateCheck(std::vector<std::string> extension_ids) {
+  if (!update_client_)
+    return;
+  update_client_->Update(extension_ids, base::Bind(&UpdateDataProvider::GetData,
+                                                   update_data_provider_),
+                         base::Bind(&UpdateCheckCompleteCallback));
 }
 
-UpdateService::~UpdateService() {
+UpdateService::UpdateService(
+    content::BrowserContext* context,
+    scoped_refptr<update_client::UpdateClient> update_client)
+    : context_(context), update_client_(update_client) {
+  CHECK(update_client_);
+  update_data_provider_ =
+      new UpdateDataProvider(context_, base::Bind(&InstallUpdateCallback));
 }
 
-void UpdateService::OnExtensionDownloadFailed(
-    const std::string& id,
-    Error error,
-    const PingResult& ping,
-    const std::set<int>& request_ids) {
-  auto callback = download_callback_;
-  download_callback_.Reset();
-  callback.Run(false);
-}
-
-void UpdateService::OnExtensionDownloadFinished(
-    const CRXFileInfo& file,
-    bool file_ownership_passed,
-    const GURL& download_url,
-    const std::string& version,
-    const PingResult& ping,
-    const std::set<int>& request_id,
-    const InstallCallback& install_callback) {
-  // TODO(rockot): Actually unpack and install the CRX.
-  auto callback = download_callback_;
-  download_callback_.Reset();
-  callback.Run(true);
-  if (!install_callback.is_null())
-    install_callback.Run(true);
-}
-
-bool UpdateService::IsExtensionPending(const std::string& id) {
-  // TODO(rockot): Implement this. For now all IDs are "pending".
-  return true;
-}
-
-bool UpdateService::GetExtensionExistingVersion(const std::string& id,
-                                                std::string* version) {
-  // TODO(rockot): Implement this.
-  return false;
-}
+UpdateService::~UpdateService() {}
 
 }  // namespace extensions
diff --git a/extensions/browser/updater/update_service.h b/extensions/browser/updater/update_service.h
index 4d19204..0ee321c 100644
--- a/extensions/browser/updater/update_service.h
+++ b/extensions/browser/updater/update_service.h
@@ -6,62 +6,53 @@
 #define EXTENSIONS_BROWSER_UPDATER_UPDATE_SERVICE_H_
 
 #include <string>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "extensions/browser/updater/extension_downloader_delegate.h"
 
 namespace content {
 class BrowserContext;
 }
 
+namespace update_client {
+class UpdateClient;
+}
+
 namespace extensions {
 
-class ExtensionDownloader;
+class UpdateDataProvider;
+class UpdateService;
 class UpdateServiceFactory;
-class UpdateServiceTest;
 
-// This service manages the download, update, and installation of extensions.
-// It is currently only used by app_shell, but should eventually replace
-// ExtensionUpdater in Chrome.
+// This service manages the autoupdate of extensions.  It should eventually
+// replace ExtensionUpdater in Chrome.
 // TODO(rockot): Replace ExtensionUpdater with this service.
-class UpdateService : public KeyedService, public ExtensionDownloaderDelegate {
+class UpdateService : public KeyedService {
  public:
   static UpdateService* Get(content::BrowserContext* context);
 
-  // TODO(rockot): Remove this. It's a placeholder for a real service interface.
-  // Downloads and (TODO) installs a CRX within the current browser context.
-  void DownloadAndInstall(const std::string& id,
-                          const base::Callback<void(bool)>& callback);
+  void Shutdown() override;
+
+  // Starts an update check for each of |extension_ids|. If there are any
+  // updates available, they will be downloaded, checked for integrity,
+  // unpacked, and then passed off to the ExtensionSystem::InstallUpdate method
+  // for install completion.
+  void StartUpdateCheck(std::vector<std::string> extension_ids);
 
  private:
   friend class UpdateServiceFactory;
-  friend class UpdateServiceTest;
 
-  explicit UpdateService(content::BrowserContext* context);
+  UpdateService(content::BrowserContext* context,
+                scoped_refptr<update_client::UpdateClient> update_client);
   ~UpdateService() override;
 
-  // ExtensionDownloaderDelegate:
-  void OnExtensionDownloadFailed(const std::string& id,
-                                 Error error,
-                                 const PingResult& ping,
-                                 const std::set<int>& request_ids) override;
-  void OnExtensionDownloadFinished(const CRXFileInfo& file,
-                                   bool file_ownership_passed,
-                                   const GURL& download_url,
-                                   const std::string& version,
-                                   const PingResult& ping,
-                                   const std::set<int>& request_id,
-                                   const InstallCallback& callback) override;
-  bool IsExtensionPending(const std::string& id) override;
-  bool GetExtensionExistingVersion(const std::string& id,
-                                   std::string* version) override;
+  content::BrowserContext* context_;
 
-  content::BrowserContext* browser_context_;
-  scoped_ptr<ExtensionDownloader> downloader_;
-  base::Callback<void(bool)> download_callback_;
+  scoped_refptr<update_client::UpdateClient> update_client_;
+  scoped_refptr<UpdateDataProvider> update_data_provider_;
 
   DISALLOW_COPY_AND_ASSIGN(UpdateService);
 };
diff --git a/extensions/browser/updater/update_service_browsertest.cc b/extensions/browser/updater/update_service_browsertest.cc
deleted file mode 100644
index 097de35..0000000
--- a/extensions/browser/updater/update_service_browsertest.cc
+++ /dev/null
@@ -1,218 +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 <map>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/run_loop.h"
-#include "base/strings/stringprintf.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "content/public/test/test_utils.h"
-#include "extensions/browser/api/extensions_api_client.h"
-#include "extensions/browser/extensions_browser_client.h"
-#include "extensions/browser/updater/update_service.h"
-#include "extensions/common/extension_urls.h"
-#include "extensions/shell/test/shell_test.h"
-#include "net/base/escape.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-
-namespace extensions {
-
-namespace {
-
-using FakeResponse = std::pair<std::string, net::HttpStatusCode>;
-
-// TODO(rockot): In general there's enough mock-Omaha-noise that this might be
-// better placed into some test library code in //components/update_client.
-FakeResponse CreateFakeUpdateResponse(const std::string& id,
-                                      size_t crx_length) {
-  std::string response_text = base::StringPrintf(
-      "<gupdate xmlns=\"http://www.google.com/update2/response\" "
-      "    protocol=\"2.0\" server=\"prod\">\n"
-      "  <daystart elapsed_days=\"2860\" elapsed_seconds=\"42042\"/>\n"
-      "  <app appid=\"%s\" status=\"ok\">\n"
-      "    <updatecheck codebase=\"%s\" fp=\"0\" hash=\"\" hash_sha256=\"\" "
-      "        size=\"%d\" status=\"ok\" version=\"1\"/>\n"
-      "  </app>\n"
-      "</gupdate>\n",
-      id.c_str(),
-      base::StringPrintf("https://fake-omaha-hostname/%s.crx",
-                         id.c_str()).c_str(),
-      static_cast<int>(crx_length));
-  return std::make_pair(response_text, net::HTTP_OK);
-}
-
-FakeResponse CreateFakeUpdateNotFoundResponse() {
-  return std::make_pair(
-      std::string(
-          "<gupdate xmlns=\"http://www.google.com/update2/response\" "
-          "         protocol=\"2.0\" server=\"prod\">\n"
-          "  <daystart elapsed_days=\"4242\" elapsed_seconds=\"42042\"/>\n"
-          "  <app appid=\"\" status=\"error-invalidAppId\">\n"
-          "</gupdate>"),
-      net::HTTP_OK);
-}
-
-bool ExtractKeyValueFromComponent(const std::string& component_str,
-                                  const std::string& target_key,
-                                  std::string* extracted_value) {
-  url::Component component(0, static_cast<int>(component_str.length()));
-  url::Component key, value;
-  while (url::ExtractQueryKeyValue(component_str.c_str(), &component, &key,
-                                   &value)) {
-    if (target_key == component_str.substr(key.begin, key.len)) {
-      *extracted_value = component_str.substr(value.begin, value.len);
-      return true;
-    }
-  }
-  return false;
-}
-
-// This extracts an extension ID from an Omaha update query. Queries have the
-// form https://foo/bar/update?x=id%3Dabcdefghijklmnopqrstuvwxyzaaaaaa%26...
-// This function extracts the 'x' query parameter (e.g. "id%3Dabcdef...."),
-// unescapes its value (to become e.g., "id=abcdef...", and then extracts the
-// 'id' value from the result (e.g. "abcdef...").
-bool ExtractIdFromUpdateQuery(const std::string& query_str, std::string* id) {
-  std::string data_string;
-  if (!ExtractKeyValueFromComponent(query_str, "x", &data_string))
-    return false;
-  data_string = net::UnescapeURLComponent(data_string,
-                                          net::UnescapeRule::URL_SPECIAL_CHARS);
-  if (!ExtractKeyValueFromComponent(data_string, "id", id))
-    return false;
-  EXPECT_EQ(32u, id->size());
-  return true;
-}
-
-void ExpectDownloadSuccess(const base::Closure& continuation, bool success) {
-  EXPECT_TRUE(success) << "Download failed.";
-  continuation.Run();
-}
-
-class FakeUpdateURLFetcherFactory : public net::URLFetcherFactory {
- public:
-  FakeUpdateURLFetcherFactory() { EXPECT_TRUE(dir_.CreateUniqueTempDir()); }
-
-  ~FakeUpdateURLFetcherFactory() override {}
-
-  void RegisterFakeExtension(const std::string& id,
-                             const std::string& contents) {
-    CHECK_EQ(32u, id.size());
-    fake_extensions_.insert(std::make_pair(id, contents));
-  }
-
-  // net::URLFetcherFactory:
-  scoped_ptr<net::URLFetcher> CreateURLFetcher(
-      int id,
-      const GURL& url,
-      net::URLFetcher::RequestType request_type,
-      net::URLFetcherDelegate* delegate) override {
-    if (url.spec().find(extension_urls::GetWebstoreUpdateUrl().spec()) == 0) {
-      // Handle fake Omaha requests.
-      return CreateUpdateManifestFetcher(url, delegate);
-    } else if (url.spec().find("https://fake-omaha-hostname") == 0) {
-      // Handle a fake CRX request.
-      return CreateCrxFetcher(url, delegate);
-    }
-    NOTREACHED();
-    return nullptr;
-  }
-
- private:
-  scoped_ptr<net::URLFetcher> CreateUpdateManifestFetcher(
-      const GURL& url,
-      net::URLFetcherDelegate* delegate) {
-    // If we have a fake CRX for the ID, return a fake update blob for it.
-    // Otherwise return an invalid-ID response.
-    FakeResponse response;
-    std::string extension_id;
-    if (!ExtractIdFromUpdateQuery(url.query(), &extension_id)) {
-      response = CreateFakeUpdateNotFoundResponse();
-    } else {
-      const auto& iter = fake_extensions_.find(extension_id);
-      if (iter == fake_extensions_.end())
-        response = CreateFakeUpdateNotFoundResponse();
-      else
-        response = CreateFakeUpdateResponse(extension_id, iter->second.size());
-    }
-    return scoped_ptr<net::URLFetcher>(
-        new net::FakeURLFetcher(url, delegate, response.first, response.second,
-                                net::URLRequestStatus::SUCCESS));
-  }
-
-  scoped_ptr<net::URLFetcher> CreateCrxFetcher(
-      const GURL& url,
-      net::URLFetcherDelegate* delegate) {
-    FakeResponse response;
-    std::string extension_id = url.path().substr(1, 32);
-    const auto& iter = fake_extensions_.find(extension_id);
-    if (iter == fake_extensions_.end())
-      response = std::make_pair(std::string(), net::HTTP_NOT_FOUND);
-    else
-      response = std::make_pair(iter->second, net::HTTP_OK);
-    net::TestURLFetcher* fetcher =
-        new net::FakeURLFetcher(url, delegate, response.first, response.second,
-                                net::URLRequestStatus::SUCCESS);
-    base::FilePath path = dir_.path().Append(
-        base::FilePath::FromUTF8Unsafe(url.path().substr(1)));
-    fetcher->SetResponseFilePath(path);
-    return scoped_ptr<net::URLFetcher>(fetcher);
-  }
-
-  base::ScopedTempDir dir_;
-
-  std::map<std::string, std::string> fake_extensions_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeUpdateURLFetcherFactory);
-};
-
-}  // namespace
-
-class UpdateServiceTest : public AppShellTest {
- public:
-  UpdateServiceTest() {}
-  ~UpdateServiceTest() override {}
-
-  void SetUpOnMainThread() override {
-    AppShellTest::SetUpOnMainThread();
-
-    update_service_ = UpdateService::Get(browser_context());
-
-    default_url_fetcher_factory_.reset(new FakeUpdateURLFetcherFactory());
-    url_fetcher_factory_.reset(
-        new net::FakeURLFetcherFactory(default_url_fetcher_factory_.get()));
-  }
-
- protected:
-  void RegisterFakeExtension(const std::string& id,
-                             const std::string& crx_contents) {
-    default_url_fetcher_factory_->RegisterFakeExtension(id, crx_contents);
-  }
-
-  UpdateService* update_service() const { return update_service_; }
-
- private:
-  scoped_ptr<FakeUpdateURLFetcherFactory> default_url_fetcher_factory_;
-  scoped_ptr<net::FakeURLFetcherFactory> url_fetcher_factory_;
-
-  UpdateService* update_service_;
-};
-
-IN_PROC_BROWSER_TEST_F(UpdateServiceTest, DownloadAndInstall) {
-  const char kCrxId[] = "abcdefghijklmnopqrstuvwxyzaaaaaa";
-  const char kCrxContents[] = "Hello, world!";
-  RegisterFakeExtension(kCrxId, kCrxContents);
-
-  base::RunLoop run_loop;
-  update_service()->DownloadAndInstall(
-      kCrxId, base::Bind(ExpectDownloadSuccess, run_loop.QuitClosure()));
-  run_loop.Run();
-}
-
-}  // namespace extensions
diff --git a/extensions/browser/updater/update_service_factory.cc b/extensions/browser/updater/update_service_factory.cc
index a87c88bd..e441dc3 100644
--- a/extensions/browser/updater/update_service_factory.cc
+++ b/extensions/browser/updater/update_service_factory.cc
@@ -5,7 +5,9 @@
 #include "extensions/browser/updater/update_service_factory.h"
 
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/update_client/update_client.h"
 #include "extensions/browser/extension_registry_factory.h"
+#include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/process_manager_factory.h"
 #include "extensions/browser/updater/update_service.h"
 
@@ -27,8 +29,6 @@
     : BrowserContextKeyedServiceFactory(
           "UpdateService",
           BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(extensions::ExtensionRegistryFactory::GetInstance());
-  DependsOn(extensions::ProcessManagerFactory::GetInstance());
 }
 
 UpdateServiceFactory::~UpdateServiceFactory() {
@@ -36,7 +36,8 @@
 
 KeyedService* UpdateServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  return new UpdateService(context);
+  return new UpdateService(
+      context, ExtensionsBrowserClient::Get()->CreateUpdateClient(context));
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/updater/update_service_unittest.cc b/extensions/browser/updater/update_service_unittest.cc
new file mode 100644
index 0000000..f570303
--- /dev/null
+++ b/extensions/browser/updater/update_service_unittest.cc
@@ -0,0 +1,248 @@
+// 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 <vector>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "base/values.h"
+#include "components/crx_file/id_util.h"
+#include "components/update_client/update_client.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extensions_test.h"
+#include "extensions/browser/mock_extension_system.h"
+#include "extensions/browser/test_extensions_browser_client.h"
+#include "extensions/browser/updater/update_service.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/common/value_builder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class FakeUpdateClient : public update_client::UpdateClient {
+ public:
+  FakeUpdateClient();
+
+  // Returns the data we've gotten from the CrxDataCallback for ids passed to
+  // the Update function.
+  std::vector<update_client::CrxComponent>* data() { return &data_; }
+
+  // update_client::UpdateClient
+  void AddObserver(Observer* observer) override {}
+  void RemoveObserver(Observer* observer) override {}
+  void Install(const std::string& id,
+               const CrxDataCallback& crx_data_callback,
+               const CompletionCallback& completion_callback) override {}
+  void Update(const std::vector<std::string>& ids,
+              const CrxDataCallback& crx_data_callback,
+              const CompletionCallback& completion_callback) override;
+  bool GetCrxUpdateState(
+      const std::string& id,
+      update_client::CrxUpdateItem* update_item) const override {
+    return false;
+  }
+  bool IsUpdating(const std::string& id) const override { return false; }
+
+ protected:
+  friend class base::RefCounted<FakeUpdateClient>;
+  ~FakeUpdateClient() override {}
+
+  std::vector<update_client::CrxComponent> data_;
+};
+
+FakeUpdateClient::FakeUpdateClient() {}
+
+void FakeUpdateClient::Update(const std::vector<std::string>& ids,
+                              const CrxDataCallback& crx_data_callback,
+                              const CompletionCallback& completion_callback) {
+  crx_data_callback.Run(ids, &data_);
+}
+
+}  // namespace
+
+namespace extensions {
+
+namespace {
+
+// A fake ExtensionSystem that lets us intercept calls to install new
+// versions of an extension.
+class FakeExtensionSystem : public MockExtensionSystem {
+ public:
+  explicit FakeExtensionSystem(content::BrowserContext* context)
+      : MockExtensionSystem(context) {}
+  ~FakeExtensionSystem() override {}
+
+  struct InstallUpdateRequest {
+    std::string extension_id;
+    base::FilePath temp_dir;
+  };
+
+  std::vector<InstallUpdateRequest>* install_requests() {
+    return &install_requests_;
+  }
+
+  void set_install_callback(const base::Closure& callback) {
+    next_install_callback_ = callback;
+  }
+
+  // ExtensionSystem override
+  void InstallUpdate(const std::string& extension_id,
+                     const base::FilePath& temp_dir) override {
+    base::DeleteFile(temp_dir, true /*recursive*/);
+    InstallUpdateRequest request;
+    request.extension_id = extension_id;
+    request.temp_dir = temp_dir;
+    install_requests_.push_back(request);
+    if (!next_install_callback_.is_null()) {
+      base::Closure tmp = next_install_callback_;
+      next_install_callback_.Reset();
+      tmp.Run();
+    }
+  }
+
+ private:
+  std::vector<InstallUpdateRequest> install_requests_;
+  base::Closure next_install_callback_;
+};
+
+class UpdateServiceTest : public ExtensionsTest {
+ public:
+  UpdateServiceTest() {
+    extensions_browser_client()->set_extension_system_factory(
+        &fake_extension_system_factory_);
+  }
+  ~UpdateServiceTest() override {}
+
+  void SetUp() override {
+    ExtensionsTest::SetUp();
+    browser_threads_.reset(new content::TestBrowserThreadBundle(
+        content::TestBrowserThreadBundle::DEFAULT));
+
+    extensions_browser_client()->SetUpdateClientFactory(base::Bind(
+        &UpdateServiceTest::CreateUpdateClient, base::Unretained(this)));
+
+    update_service_ = UpdateService::Get(browser_context());
+  }
+
+ protected:
+  UpdateService* update_service() const { return update_service_; }
+  FakeUpdateClient* update_client() const { return update_client_.get(); }
+
+  update_client::UpdateClient* CreateUpdateClient() {
+    // We only expect that this will get called once, so consider it an error
+    // if our update_client_ is already non-null.
+    EXPECT_EQ(nullptr, update_client_.get());
+    update_client_ = new FakeUpdateClient();
+    return update_client_.get();
+  }
+
+  // Helper function that creates a file at |relative_path| within |directory|
+  // and fills it with |content|.
+  bool AddFileToDirectory(const base::FilePath& directory,
+                          const base::FilePath& relative_path,
+                          const std::string& content) {
+    base::FilePath full_path = directory.Append(relative_path);
+    if (!CreateDirectory(full_path.DirName()))
+      return false;
+    int result = base::WriteFile(full_path, content.data(), content.size());
+    return (static_cast<size_t>(result) == content.size());
+  }
+
+  FakeExtensionSystem* extension_system() {
+    return static_cast<FakeExtensionSystem*>(
+        fake_extension_system_factory_.GetForBrowserContext(browser_context()));
+  }
+
+ private:
+  UpdateService* update_service_;
+  scoped_refptr<FakeUpdateClient> update_client_;
+  scoped_ptr<content::TestBrowserThreadBundle> browser_threads_;
+  MockExtensionSystemFactory<FakeExtensionSystem>
+      fake_extension_system_factory_;
+};
+
+TEST_F(UpdateServiceTest, BasicUpdateOperations) {
+  // Create a temporary directory that a fake extension will live in and fill
+  // it with some test files.
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath foo_js(FILE_PATH_LITERAL("foo.js"));
+  base::FilePath bar_html(FILE_PATH_LITERAL("bar/bar.html"));
+  ASSERT_TRUE(AddFileToDirectory(temp_dir.path(), foo_js, "hello"))
+      << "Failed to write " << temp_dir.path().value() << "/" << foo_js.value();
+  ASSERT_TRUE(AddFileToDirectory(temp_dir.path(), bar_html, "world"));
+
+  ExtensionBuilder builder;
+  builder.SetManifest(DictionaryBuilder()
+                          .Set("name", "Foo")
+                          .Set("version", "1.0")
+                          .Set("manifest_version", 2));
+  builder.SetID(crx_file::id_util::GenerateId("whatever"));
+  builder.SetPath(temp_dir.path());
+
+  scoped_refptr<Extension> extension1(builder.Build());
+
+  ExtensionRegistry::Get(browser_context())->AddEnabled(extension1);
+  std::vector<std::string> ids;
+  ids.push_back(extension1->id());
+
+  // Start an update check and verify that the UpdateClient was sent the right
+  // data.
+  update_service()->StartUpdateCheck(ids);
+  std::vector<update_client::CrxComponent>* data = update_client()->data();
+  ASSERT_NE(nullptr, data);
+  ASSERT_EQ(1u, data->size());
+
+  ASSERT_TRUE(data->at(0).version.Equals(*extension1->version()));
+  update_client::CrxInstaller* installer = data->at(0).installer.get();
+  ASSERT_NE(installer, nullptr);
+
+  // The GetInstalledFile method is used when processing differential updates
+  // to get a path to an existing file in an extension. We want to test a
+  // number of scenarios to be user we handle invalid relative paths, don't
+  // accidentally return paths outside the extension's dir, etc.
+  base::FilePath tmp;
+  EXPECT_TRUE(installer->GetInstalledFile(foo_js.MaybeAsASCII(), &tmp));
+  EXPECT_EQ(temp_dir.path().Append(foo_js), tmp) << tmp.value();
+
+  EXPECT_TRUE(installer->GetInstalledFile(bar_html.MaybeAsASCII(), &tmp));
+  EXPECT_EQ(temp_dir.path().Append(bar_html), tmp) << tmp.value();
+
+  EXPECT_FALSE(installer->GetInstalledFile("does_not_exist", &tmp));
+  EXPECT_FALSE(installer->GetInstalledFile("does/not/exist", &tmp));
+  EXPECT_FALSE(installer->GetInstalledFile("/does/not/exist", &tmp));
+  EXPECT_FALSE(installer->GetInstalledFile("C:\\tmp", &tmp));
+
+  base::FilePath system_temp_dir;
+  ASSERT_TRUE(base::GetTempDir(&system_temp_dir));
+  EXPECT_FALSE(
+      installer->GetInstalledFile(system_temp_dir.MaybeAsASCII(), &tmp));
+
+  // Test the install callback.
+  base::ScopedTempDir new_version_dir;
+  ASSERT_TRUE(new_version_dir.CreateUniqueTempDir());
+  scoped_ptr<base::DictionaryValue> new_manifest(
+      extension1->manifest()->value()->DeepCopy());
+  new_manifest->SetString("version", "2.0");
+
+  installer->Install(*new_manifest, new_version_dir.path());
+
+  scoped_refptr<content::MessageLoopRunner> loop_runner =
+      new content::MessageLoopRunner();
+  extension_system()->set_install_callback(loop_runner->QuitClosure());
+  loop_runner->Run();
+
+  std::vector<FakeExtensionSystem::InstallUpdateRequest>* requests =
+      extension_system()->install_requests();
+  ASSERT_EQ(1u, requests->size());
+  EXPECT_EQ(requests->at(0).extension_id, extension1->id());
+  EXPECT_NE(requests->at(0).temp_dir.value(), new_version_dir.path().value());
+}
+
+}  // namespace
+
+}  // namespace extensions
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn
index 3a557d3..c0bff59 100644
--- a/extensions/common/BUILD.gn
+++ b/extensions/common/BUILD.gn
@@ -41,10 +41,12 @@
       "//build/config/compiler:no_size_t_to_int_warning",
     ]
 
-    deps = [
+    public_deps = [
       ":common_constants",
       ":mojo",
+    ]
 
+    deps = [
       # TODO(benwells): figure out what to do with the api target and
       # api resources compiled into the chrome resource bundle.
       # http://crbug.com/162530
diff --git a/extensions/common/api/BUILD.gn b/extensions/common/api/BUILD.gn
index 474e041..b589fd23 100644
--- a/extensions/common/api/BUILD.gn
+++ b/extensions/common/api/BUILD.gn
@@ -24,8 +24,8 @@
 }
 
 # GYP version: extensions/common/api/api.gyp:extensions_api
-source_set("api") {
-  deps = [
+group("api") {
+  public_deps = [
     ":mojom",
     ":generated_api",
   ]
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index c7976da..3c7657e 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -111,7 +111,9 @@
         '../components/components.gyp:sessions_content',
         '../components/components.gyp:storage_monitor',
         '../components/components.gyp:ui_zoom',
+        '../components/components.gyp:update_client',
         '../components/components.gyp:variations',
+        '../components/components.gyp:version_info',
         '../components/components.gyp:web_cache_browser',
         '../components/components.gyp:web_modal',
         '../content/content.gyp:content_browser',
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi
index 450a943..d730681 100644
--- a/extensions/extensions.gypi
+++ b/extensions/extensions.gypi
@@ -752,6 +752,12 @@
       'browser/updater/request_queue_impl.h',
       'browser/updater/safe_manifest_parser.cc',
       'browser/updater/safe_manifest_parser.h',
+      'browser/updater/update_client_config.cc',
+      'browser/updater/update_client_config.h',
+      'browser/updater/update_data_provider.cc',
+      'browser/updater/update_data_provider.h',
+      'browser/updater/update_install_shim.cc',
+      'browser/updater/update_install_shim.h',
       'browser/updater/update_service.cc',
       'browser/updater/update_service.h',
       'browser/updater/update_service_factory.cc',
diff --git a/extensions/extensions_tests.gypi b/extensions/extensions_tests.gypi
index 2019e37c..aab6570 100644
--- a/extensions/extensions_tests.gypi
+++ b/extensions/extensions_tests.gypi
@@ -27,7 +27,6 @@
       'browser/guest_view/web_view/web_view_apitest.cc',
       'browser/guest_view/web_view/web_view_apitest.h',
       'browser/guest_view/web_view/web_view_media_access_apitest.cc',
-      'browser/updater/update_service_browsertest.cc',
       'shell/browser/geolocation/geolocation_apitest.cc',
       'shell/browser/shell_browsertest.cc',
       'shell/test/shell_apitest.cc',
@@ -98,6 +97,7 @@
       'browser/extension_throttle_test_support.cc',
       'browser/extension_throttle_test_support.h',
       'browser/extension_throttle_unittest.cc',
+      'browser/updater/update_service_unittest.cc',
       'browser/value_store/leveldb_value_store_unittest.cc',
       'browser/value_store/testing_value_store_unittest.cc',
       'browser/value_store/value_store_change_unittest.cc',
diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc
index 073dacb..01536790 100644
--- a/extensions/shell/browser/shell_browser_main_parts.cc
+++ b/extensions/shell/browser/shell_browser_main_parts.cc
@@ -73,13 +73,6 @@
 
 namespace extensions {
 
-namespace {
-
-void CrxInstallComplete(bool success) {
-  VLOG(1) << "CRX download complete. Success: " << success;
-}
-}
-
 ShellBrowserMainParts::ShellBrowserMainParts(
     const content::MainFunctionParams& parameters,
     ShellBrowserMainDelegate* browser_main_delegate)
@@ -211,17 +204,6 @@
       base::Bind(nacl::NaClProcessHost::EarlyStartup));
 #endif
 
-  // TODO(rockot): Remove this temporary hack test.
-  std::string install_crx_id =
-      cmd->GetSwitchValueASCII(switches::kAppShellInstallCrx);
-  if (install_crx_id.size() != 0) {
-    CHECK(install_crx_id.size() == 32)
-        << "Extension ID must be exactly 32 characters long.";
-    UpdateService* update_service = UpdateService::Get(browser_context_.get());
-    update_service->DownloadAndInstall(install_crx_id,
-                                       base::Bind(CrxInstallComplete));
-  }
-
   devtools_http_handler_.reset(
       content::ShellDevToolsManagerDelegate::CreateHttpHandler(
           browser_context_.get()));
diff --git a/extensions/shell/browser/shell_extension_system.cc b/extensions/shell/browser/shell_extension_system.cc
index 0457491..b6cff6a 100644
--- a/extensions/shell/browser/shell_extension_system.cc
+++ b/extensions/shell/browser/shell_extension_system.cc
@@ -176,6 +176,12 @@
   return make_scoped_ptr(new ExtensionSet());
 }
 
+void ShellExtensionSystem::InstallUpdate(const std::string& extension_id,
+                                         const base::FilePath& temp_dir) {
+  NOTREACHED();
+  base::DeleteFile(temp_dir, true /* recursive */);
+}
+
 void ShellExtensionSystem::OnExtensionRegisteredWithRequestContexts(
     scoped_refptr<Extension> extension) {
   ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
diff --git a/extensions/shell/browser/shell_extension_system.h b/extensions/shell/browser/shell_extension_system.h
index f042f2d7..ca2cb5e 100644
--- a/extensions/shell/browser/shell_extension_system.h
+++ b/extensions/shell/browser/shell_extension_system.h
@@ -64,6 +64,8 @@
   ContentVerifier* content_verifier() override;
   scoped_ptr<ExtensionSet> GetDependentExtensions(
       const Extension* extension) override;
+  void InstallUpdate(const std::string& extension_id,
+                     const base::FilePath& temp_dir) override;
 
  private:
   void OnExtensionRegisteredWithRequestContexts(
diff --git a/extensions/shell/common/switches.cc b/extensions/shell/common/switches.cc
index fbb5783..66bd7e5 100644
--- a/extensions/shell/common/switches.cc
+++ b/extensions/shell/common/switches.cc
@@ -13,9 +13,6 @@
 // Size for the host window to create (i.e. "800x600").
 const char kAppShellHostWindowSize[] = "app-shell-host-window-size";
 
-// ID of an extension CRX to be downloaded from the web store.
-const char kAppShellInstallCrx[] = "app-shell-install-crx";
-
 // SSID of the preferred WiFi network.
 const char kAppShellPreferredNetwork[] = "app-shell-preferred-network";
 
diff --git a/extensions/shell/common/switches.h b/extensions/shell/common/switches.h
index b6b3932..7cfe1d6 100644
--- a/extensions/shell/common/switches.h
+++ b/extensions/shell/common/switches.h
@@ -12,7 +12,6 @@
 // alongside the definition of their values in the .cc file.
 extern const char kAppShellAllowRoaming[];
 extern const char kAppShellHostWindowSize[];
-extern const char kAppShellInstallCrx[];
 extern const char kAppShellPreferredNetwork[];
 extern const char kAppShellRefreshToken[];
 extern const char kAppShellUser[];
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index 5a4e50be..0f3d585 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -69,9 +69,8 @@
   "+third_party/google_toolbox_for_mac",
   "+ui",
 
-  # Those don't works on iOS or depends on //content, exclude them.
+  # Those depend on //content; exclude them.
   "-components/metrics/gpu",
-  "-components/metrics/profiler",
 
   # For tests.
   "+ios/chrome/test",
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.cc b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.cc
new file mode 100644
index 0000000..06a35333
--- /dev/null
+++ b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.cc
@@ -0,0 +1,327 @@
+// 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 "ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service.h"
+#include "base/process/process_metrics.h"
+#include "base/rand_util.h"
+#include "base/strings/string16.h"
+#include "base/threading/platform_thread.h"
+#include "components/crash/core/common/crash_keys.h"
+#include "components/metrics/call_stack_profile_metrics_provider.h"
+#include "components/metrics/drive_metrics_provider.h"
+#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/metrics_service.h"
+#include "components/metrics/net/net_metrics_log_uploader.h"
+#include "components/metrics/net/network_metrics_provider.h"
+#include "components/metrics/net/version_utils.h"
+#include "components/metrics/profiler/profiler_metrics_provider.h"
+#include "components/metrics/profiler/tracking_synchronizer.h"
+#include "components/metrics/stability_metrics_helper.h"
+#include "components/metrics/ui/screen_info_metrics_provider.h"
+#include "components/metrics/url_constants.h"
+#include "components/omnibox/browser/omnibox_metrics_provider.h"
+#include "components/signin/core/browser/signin_status_metrics_provider.h"
+#include "components/variations/variations_associated_data.h"
+#include "components/version_info/version_info.h"
+#include "ios/chrome/browser/application_context.h"
+#include "ios/chrome/browser/chrome_paths.h"
+#include "ios/chrome/browser/google/google_brand.h"
+#include "ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.h"
+#include "ios/chrome/browser/metrics/ios_stability_metrics_provider.h"
+#include "ios/chrome/browser/signin/ios_chrome_signin_status_metrics_provider_delegate.h"
+#include "ios/chrome/browser/tab_parenting_global_observer.h"
+#include "ios/chrome/browser/ui/browser_otr_state.h"
+#include "ios/chrome/common/channel_info.h"
+#include "ios/web/public/web_thread.h"
+
+namespace {
+
+// Standard interval between log uploads, in seconds.
+const int kStandardUploadIntervalSeconds = 5 * 60;           // Five minutes.
+const int kStandardUploadIntervalCellularSeconds = 15 * 60;  // Fifteen minutes.
+
+// Returns true if current connection type is cellular and user is assigned to
+// experimental group for enabled cellular uploads.
+bool IsCellularLogicEnabled() {
+  if (variations::GetVariationParamValue("UMA_EnableCellularLogUpload",
+                                         "Enabled") != "true" ||
+      variations::GetVariationParamValue("UMA_EnableCellularLogUpload",
+                                         "Optimize") == "false") {
+    return false;
+  }
+
+  return net::NetworkChangeNotifier::IsConnectionCellular(
+      net::NetworkChangeNotifier::GetConnectionType());
+}
+
+}  // namespace
+
+IOSChromeMetricsServiceClient::IOSChromeMetricsServiceClient(
+    metrics::MetricsStateManager* state_manager)
+    : metrics_state_manager_(state_manager),
+      stability_metrics_provider_(nullptr),
+      profiler_metrics_provider_(nullptr),
+      drive_metrics_provider_(nullptr),
+      start_time_(base::TimeTicks::Now()),
+      has_uploaded_profiler_data_(false),
+      weak_ptr_factory_(this) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  RegisterForNotifications();
+}
+
+IOSChromeMetricsServiceClient::~IOSChromeMetricsServiceClient() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+// static
+scoped_ptr<IOSChromeMetricsServiceClient> IOSChromeMetricsServiceClient::Create(
+    metrics::MetricsStateManager* state_manager,
+    PrefService* local_state) {
+  // Perform two-phase initialization so that |client->metrics_service_| only
+  // receives pointers to fully constructed objects.
+  scoped_ptr<IOSChromeMetricsServiceClient> client(
+      new IOSChromeMetricsServiceClient(state_manager));
+  client->Initialize();
+
+  return client.Pass();
+}
+
+// static
+void IOSChromeMetricsServiceClient::RegisterPrefs(
+    PrefRegistrySimple* registry) {
+  metrics::MetricsService::RegisterPrefs(registry);
+  metrics::StabilityMetricsHelper::RegisterPrefs(registry);
+}
+
+void IOSChromeMetricsServiceClient::SetMetricsClientId(
+    const std::string& client_id) {
+  crash_keys::SetMetricsClientIdFromGUID(client_id);
+}
+
+void IOSChromeMetricsServiceClient::OnRecordingDisabled() {
+  crash_keys::ClearMetricsClientId();
+}
+
+bool IOSChromeMetricsServiceClient::IsOffTheRecordSessionActive() {
+  return ::IsOffTheRecordSessionActive();
+}
+
+int32 IOSChromeMetricsServiceClient::GetProduct() {
+  return metrics::ChromeUserMetricsExtension::CHROME;
+}
+
+std::string IOSChromeMetricsServiceClient::GetApplicationLocale() {
+  return GetApplicationContext()->GetApplicationLocale();
+}
+
+bool IOSChromeMetricsServiceClient::GetBrand(std::string* brand_code) {
+  return ios::google_brand::GetBrand(brand_code);
+}
+
+metrics::SystemProfileProto::Channel
+IOSChromeMetricsServiceClient::GetChannel() {
+  return metrics::AsProtobufChannel(::GetChannel());
+}
+
+std::string IOSChromeMetricsServiceClient::GetVersionString() {
+  return metrics::GetVersionString();
+}
+
+void IOSChromeMetricsServiceClient::OnLogUploadComplete() {}
+
+void IOSChromeMetricsServiceClient::InitializeSystemProfileMetrics(
+    const base::Closure& done_callback) {
+  finished_init_task_callback_ = done_callback;
+  drive_metrics_provider_->GetDriveMetrics(
+      base::Bind(&IOSChromeMetricsServiceClient::OnInitTaskGotDriveMetrics,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void IOSChromeMetricsServiceClient::CollectFinalMetricsForLog(
+    const base::Closure& done_callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  collect_final_metrics_done_callback_ = done_callback;
+
+  if (ShouldIncludeProfilerDataInLog()) {
+    // Fetch profiler data. This will call into
+    // |FinishedReceivingProfilerData()| when the task completes.
+    metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously(
+        weak_ptr_factory_.GetWeakPtr());
+  } else {
+    CollectFinalHistograms();
+  }
+}
+
+scoped_ptr<metrics::MetricsLogUploader>
+IOSChromeMetricsServiceClient::CreateUploader(
+    const base::Callback<void(int)>& on_upload_complete) {
+  return scoped_ptr<metrics::MetricsLogUploader>(
+      new metrics::NetMetricsLogUploader(
+          GetApplicationContext()->GetSystemURLRequestContext(),
+          metrics::kDefaultMetricsServerUrl, metrics::kDefaultMetricsMimeType,
+          on_upload_complete));
+}
+
+base::TimeDelta IOSChromeMetricsServiceClient::GetStandardUploadInterval() {
+  if (IsCellularLogicEnabled())
+    return base::TimeDelta::FromSeconds(kStandardUploadIntervalCellularSeconds);
+  return base::TimeDelta::FromSeconds(kStandardUploadIntervalSeconds);
+}
+
+base::string16 IOSChromeMetricsServiceClient::GetRegistryBackupKey() {
+  return base::string16();
+}
+
+void IOSChromeMetricsServiceClient::WebStateDidStartLoading(
+    web::WebState* web_state) {
+  metrics_service_->OnApplicationNotIdle();
+}
+
+void IOSChromeMetricsServiceClient::WebStateDidStopLoading(
+    web::WebState* web_state) {
+  metrics_service_->OnApplicationNotIdle();
+}
+
+void IOSChromeMetricsServiceClient::LogRendererProcessCrash() {
+  stability_metrics_provider_->LogRendererCrash();
+}
+
+void IOSChromeMetricsServiceClient::Initialize() {
+  metrics_service_.reset(new metrics::MetricsService(
+      metrics_state_manager_, this, GetApplicationContext()->GetLocalState()));
+
+  // Register metrics providers.
+  metrics_service_->RegisterMetricsProvider(
+      scoped_ptr<metrics::MetricsProvider>(new metrics::NetworkMetricsProvider(
+          web::WebThread::GetBlockingPool())));
+
+  // Currently, we configure OmniboxMetricsProvider to not log events to UMA
+  // if there is a single incognito session visible. In the future, it may
+  // be worth revisiting this to still log events from non-incognito sessions.
+  metrics_service_->RegisterMetricsProvider(
+      scoped_ptr<metrics::MetricsProvider>(new OmniboxMetricsProvider(
+          base::Bind(&::IsOffTheRecordSessionActive))));
+
+  stability_metrics_provider_ = new IOSChromeStabilityMetricsProvider(
+      GetApplicationContext()->GetLocalState());
+  metrics_service_->RegisterMetricsProvider(
+      scoped_ptr<metrics::MetricsProvider>(stability_metrics_provider_));
+
+  metrics_service_->RegisterMetricsProvider(
+      scoped_ptr<metrics::MetricsProvider>(
+          new metrics::ScreenInfoMetricsProvider));
+
+  drive_metrics_provider_ = new metrics::DriveMetricsProvider(
+      web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE),
+      ios::FILE_LOCAL_STATE);
+  metrics_service_->RegisterMetricsProvider(
+      scoped_ptr<metrics::MetricsProvider>(drive_metrics_provider_));
+
+  profiler_metrics_provider_ =
+      new metrics::ProfilerMetricsProvider(base::Bind(&IsCellularLogicEnabled));
+  metrics_service_->RegisterMetricsProvider(
+      scoped_ptr<metrics::MetricsProvider>(profiler_metrics_provider_));
+
+  metrics_service_->RegisterMetricsProvider(
+      scoped_ptr<metrics::MetricsProvider>(
+          new metrics::CallStackProfileMetricsProvider));
+
+  metrics_service_->RegisterMetricsProvider(
+      scoped_ptr<metrics::MetricsProvider>(
+          SigninStatusMetricsProvider::CreateInstance(make_scoped_ptr(
+              new IOSChromeSigninStatusMetricsProviderDelegate))));
+
+  scoped_ptr<metrics::MetricsProvider> ios_stability_metrics_provider(
+      new IOSStabilityMetricsProvider(metrics_service_.get()));
+  if (ios_stability_metrics_provider) {
+    metrics_service_->RegisterMetricsProvider(
+        ios_stability_metrics_provider.Pass());
+  } else {
+    NOTREACHED() << "No IOSStabilityMetricsProvider registered.";
+  }
+}
+
+void IOSChromeMetricsServiceClient::OnInitTaskGotDriveMetrics() {
+  finished_init_task_callback_.Run();
+}
+
+bool IOSChromeMetricsServiceClient::ShouldIncludeProfilerDataInLog() {
+  // Upload profiler data at most once per session.
+  if (has_uploaded_profiler_data_)
+    return false;
+
+  // For each log, flip a fair coin. Thus, profiler data is sent with the first
+  // log with probability 50%, with the second log with probability 25%, and so
+  // on. As a result, uploaded data is biased toward earlier logs.
+  // TODO(isherman): Explore other possible algorithms, and choose one that
+  // might be more appropriate.  For example, it might be reasonable to include
+  // profiler data with some fixed probability, so that a given client might
+  // upload profiler data more than once; but on average, clients won't upload
+  // too much data.
+  if (base::RandDouble() < 0.5)
+    return false;
+
+  has_uploaded_profiler_data_ = true;
+  return true;
+}
+
+void IOSChromeMetricsServiceClient::ReceivedProfilerData(
+    const metrics::ProfilerDataAttributes& attributes,
+    const tracked_objects::ProcessDataPhaseSnapshot& process_data_phase,
+    const metrics::ProfilerEvents& past_events) {
+  profiler_metrics_provider_->RecordProfilerData(
+      process_data_phase, attributes.process_id, attributes.process_type,
+      attributes.profiling_phase, attributes.phase_start - start_time_,
+      attributes.phase_finish - start_time_, past_events);
+}
+
+void IOSChromeMetricsServiceClient::FinishedReceivingProfilerData() {
+  CollectFinalHistograms();
+}
+
+void IOSChromeMetricsServiceClient::CollectFinalHistograms() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // TODO(ios): Try to extract the flow below into a utility function that is
+  // shared between the iOS port's usage and
+  // ChromeMetricsServiceClient::CollectFinalHistograms()'s usage of
+  // MetricsMemoryDetails.
+  scoped_ptr<base::ProcessMetrics> process_metrics(
+      base::ProcessMetrics::CreateProcessMetrics(
+          base::GetCurrentProcessHandle()));
+  UMA_HISTOGRAM_MEMORY_KB("Memory.Browser",
+                          process_metrics->GetWorkingSetSize() / 1024);
+  collect_final_metrics_done_callback_.Run();
+}
+
+void IOSChromeMetricsServiceClient::RegisterForNotifications() {
+  tab_parented_subscription_ =
+      TabParentingGlobalObserver::GetInstance()->RegisterCallback(
+          base::Bind(&IOSChromeMetricsServiceClient::OnTabParented,
+                     base::Unretained(this)));
+  omnibox_url_opened_subscription_ =
+      OmniboxEventGlobalTracker::GetInstance()->RegisterCallback(
+          base::Bind(&IOSChromeMetricsServiceClient::OnURLOpenedFromOmnibox,
+                     base::Unretained(this)));
+}
+
+void IOSChromeMetricsServiceClient::OnTabParented(web::WebState* web_state) {
+  metrics_service_->OnApplicationNotIdle();
+}
+
+void IOSChromeMetricsServiceClient::OnURLOpenedFromOmnibox(OmniboxLog* log) {
+  metrics_service_->OnApplicationNotIdle();
+}
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h
new file mode 100644
index 0000000..bc9842f
--- /dev/null
+++ b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h
@@ -0,0 +1,168 @@
+// 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 IOS_CHROME_BROWSER_METRICS_IOS_CHROME_METRICS_SERVICE_CLIENT_H_
+#define IOS_CHROME_BROWSER_METRICS_IOS_CHROME_METRICS_SERVICE_CLIENT_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "components/metrics/metrics_service_client.h"
+#include "components/metrics/profiler/tracking_synchronizer_observer.h"
+#include "components/omnibox/browser/omnibox_event_global_tracker.h"
+#include "ios/web/public/web_state/global_web_state_observer.h"
+
+class IOSChromeStabilityMetricsProvider;
+class PrefRegistrySimple;
+class PrefService;
+
+namespace base {
+class FilePath;
+}  // namespace base
+
+namespace metrics {
+class DriveMetricsProvider;
+class MetricsService;
+class MetricsStateManager;
+class ProfilerMetricsProvider;
+}  // namespace metrics
+
+// IOSChromeMetricsServiceClient provides an implementation of
+// MetricsServiceClient that depends on //ios/chrome/.
+class IOSChromeMetricsServiceClient
+    : public metrics::MetricsServiceClient,
+      public metrics::TrackingSynchronizerObserver,
+      public web::GlobalWebStateObserver {
+ public:
+  ~IOSChromeMetricsServiceClient() override;
+
+  // Factory function.
+  static scoped_ptr<IOSChromeMetricsServiceClient> Create(
+      metrics::MetricsStateManager* state_manager,
+      PrefService* local_state);
+
+  // Registers local state prefs used by this class.
+  static void RegisterPrefs(PrefRegistrySimple* registry);
+
+  // metrics::MetricsServiceClient:
+  void SetMetricsClientId(const std::string& client_id) override;
+  void OnRecordingDisabled() override;
+  bool IsOffTheRecordSessionActive() override;
+  int32 GetProduct() override;
+  std::string GetApplicationLocale() override;
+  bool GetBrand(std::string* brand_code) override;
+  metrics::SystemProfileProto::Channel GetChannel() override;
+  std::string GetVersionString() override;
+  void OnLogUploadComplete() override;
+  void InitializeSystemProfileMetrics(
+      const base::Closure& done_callback) override;
+  void CollectFinalMetricsForLog(const base::Closure& done_callback) override;
+  scoped_ptr<metrics::MetricsLogUploader> CreateUploader(
+      const base::Callback<void(int)>& on_upload_complete) override;
+  base::TimeDelta GetStandardUploadInterval() override;
+  base::string16 GetRegistryBackupKey() override;
+
+  // web::GlobalWebStateObserver:
+  void WebStateDidStartLoading(web::WebState* web_state) override;
+  void WebStateDidStopLoading(web::WebState* web_state) override;
+
+  metrics::MetricsService* metrics_service() { return metrics_service_.get(); }
+
+  // Records an unexpected renderer (web) process termination.
+  // This path only exists on iOS because the other platforms use the (now
+  // deprecated) content::Notification system to get this information into the
+  // stability provider.
+  void LogRendererProcessCrash();
+
+ private:
+  explicit IOSChromeMetricsServiceClient(
+      metrics::MetricsStateManager* state_manager);
+
+  // Completes the two-phase initialization of IOSChromeMetricsServiceClient.
+  void Initialize();
+
+  // Called after the drive metrics init task has been completed that continues
+  // the init task by loading profiler data.
+  void OnInitTaskGotDriveMetrics();
+
+  // Returns true iff profiler data should be included in the next metrics log.
+  // NOTE: This method is probabilistic and also updates internal state as a
+  // side-effect when called, so it should only be called once per log.
+  bool ShouldIncludeProfilerDataInLog();
+
+  // TrackingSynchronizerObserver:
+  void ReceivedProfilerData(
+      const metrics::ProfilerDataAttributes& attributes,
+      const tracked_objects::ProcessDataPhaseSnapshot& process_data_phase,
+      const metrics::ProfilerEvents& past_profiler_events) override;
+  void FinishedReceivingProfilerData() override;
+
+  // Callbacks for various stages of final log info collection. Do not call
+  // these directly.
+  void CollectFinalHistograms();
+
+  // Registers |this| as an observer for notifications which indicate that a
+  // user is performing work. This is useful to allow some features to sleep,
+  // until the machine becomes active, such as precluding UMA uploads unless
+  // there was recent activity.
+  void RegisterForNotifications();
+
+  // Called when a tab is parented.
+  void OnTabParented(web::WebState* web_state);
+
+  // Called when a URL is opened from the Omnibox.
+  void OnURLOpenedFromOmnibox(OmniboxLog* log);
+
+  base::ThreadChecker thread_checker_;
+
+  // Weak pointer to the MetricsStateManager.
+  metrics::MetricsStateManager* metrics_state_manager_;
+
+  // The MetricsService that |this| is a client of.
+  scoped_ptr<metrics::MetricsService> metrics_service_;
+
+  // The IOSChromeStabilityMetricsProvider instance that was registered with
+  // MetricsService. Has the same lifetime as |metrics_service_|.
+  IOSChromeStabilityMetricsProvider* stability_metrics_provider_;
+
+  // Saved callback received from CollectFinalMetricsForLog().
+  base::Closure collect_final_metrics_done_callback_;
+
+  // The ProfilerMetricsProvider instance that was registered with
+  // MetricsService. Has the same lifetime as |metrics_service_|.
+  metrics::ProfilerMetricsProvider* profiler_metrics_provider_;
+
+  // The DriveMetricsProvider instance that was registered with MetricsService.
+  // Has the same lifetime as |metrics_service_|.
+  metrics::DriveMetricsProvider* drive_metrics_provider_;
+
+  // Callback that is called when initial metrics gathering is complete.
+  base::Closure finished_init_task_callback_;
+
+  // Time of this object's creation.
+  const base::TimeTicks start_time_;
+
+  // Subscription for receiving callbacks that a tab was parented.
+  scoped_ptr<base::CallbackList<void(web::WebState*)>::Subscription>
+      tab_parented_subscription_;
+
+  // Subscription for receiving callbacks that a URL was opened from the
+  // omnibox.
+  scoped_ptr<base::CallbackList<void(OmniboxLog*)>::Subscription>
+      omnibox_url_opened_subscription_;
+
+  // Whether this client has already uploaded profiler data during this session.
+  // Profiler data is uploaded at most once per session.
+  bool has_uploaded_profiler_data_;
+
+  base::WeakPtrFactory<IOSChromeMetricsServiceClient> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(IOSChromeMetricsServiceClient);
+};
+
+#endif  // IOS_CHROME_BROWSER_METRICS_IOS_CHROME_METRICS_SERVICE_CLIENT_H_
diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp
index 9a156121..9a63991 100644
--- a/ios/chrome/ios_chrome.gyp
+++ b/ios/chrome/ios_chrome.gyp
@@ -288,6 +288,8 @@
         'browser/metrics/field_trial_synchronizer.h',
         'browser/metrics/ios_chrome_metrics_service_accessor.cc',
         'browser/metrics/ios_chrome_metrics_service_accessor.h',
+        'browser/metrics/ios_chrome_metrics_service_client.cc',
+        'browser/metrics/ios_chrome_metrics_service_client.h',
         'browser/metrics/ios_chrome_stability_metrics_provider.cc',
         'browser/metrics/ios_chrome_stability_metrics_provider.h',
         'browser/metrics/ios_stability_metrics_provider.h',
diff --git a/ios/web/ios_web.gyp b/ios/web/ios_web.gyp
index a1ab0fff..891985a 100644
--- a/ios/web/ios_web.gyp
+++ b/ios/web/ios_web.gyp
@@ -269,6 +269,8 @@
         'web_state/ui/crw_web_controller_container_view.h',
         'web_state/ui/crw_web_controller_container_view.mm',
         'web_state/ui/crw_web_view_content_view.mm',
+        'web_state/ui/crw_wk_script_message_router.h',
+        'web_state/ui/crw_wk_script_message_router.mm',
         'web_state/ui/crw_wk_simple_web_view_controller.h',
         'web_state/ui/crw_wk_simple_web_view_controller.mm',
         'web_state/ui/crw_wk_web_view_crash_detector.h',
diff --git a/ios/web/ios_web_unittests.gyp b/ios/web/ios_web_unittests.gyp
index f6df39f..8c7c517b 100644
--- a/ios/web/ios_web_unittests.gyp
+++ b/ios/web/ios_web_unittests.gyp
@@ -68,6 +68,7 @@
         'web_state/ui/crw_web_controller_container_view_unittest.mm',
         'web_state/ui/crw_web_controller_observer_unittest.mm',
         'web_state/ui/crw_web_controller_unittest.mm',
+        'web_state/ui/crw_wk_script_message_router_unittest.mm',
         'web_state/ui/crw_wk_simple_web_view_controller_unittest.mm',
         'web_state/ui/crw_wk_web_view_crash_detector_unittest.mm',
         'web_state/ui/web_view_js_utils_unittest.mm',
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index b0e29973..980b135d 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -381,7 +381,6 @@
     id result = [[OCMockObject mockForClass:[WKWebView class]] retain];
 
     // Called by resetInjectedWebView
-    [[result stub] configuration];
     [[result stub] backForwardList];
     [[result stub] setNavigationDelegate:OCMOCK_ANY];
     [[result stub] setUIDelegate:OCMOCK_ANY];
diff --git a/ios/web/web_state/ui/crw_wk_script_message_router.h b/ios/web/web_state/ui/crw_wk_script_message_router.h
new file mode 100644
index 0000000..bb6b2a2d
--- /dev/null
+++ b/ios/web/web_state/ui/crw_wk_script_message_router.h
@@ -0,0 +1,43 @@
+// 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 IOS_WEB_WEB_STATE_UI_CRW_WK_SCRIPT_MESSAGE_ROUTER_H_
+#define IOS_WEB_WEB_STATE_UI_CRW_WK_SCRIPT_MESSAGE_ROUTER_H_
+
+#import <WebKit/WebKit.h>
+
+// WKUserContentController wrapper that allows adding multiple message handlers
+// for the same message name. CRWWKScriptMessageRouter will route the messages
+// from the underlying user content controller to a designated reciever by
+// matching the message's name and webView.
+@interface CRWWKScriptMessageRouter : NSObject
+
+// Underlying WKUserContentController.
+@property(nonatomic, readonly) WKUserContentController* userContentController;
+
+// Designated initializer. |userContentController| must not be nil.
+- (instancetype)initWithUserContentController:
+    (WKUserContentController*)userContentController NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+// Sets a script message handler. Multiple message handlers can be added for
+// the same message name and long as |webView| are different. Setting |handler|
+// for the same |name| and |webView| pair is an error. |handler| will be called
+// if WKScriptMessage sent by WKUserContentController will match both the |name|
+// and the |webView|.
+- (void)setScriptMessageHandler:(void (^)(WKScriptMessage*))handler
+                           name:(NSString*)messageName
+                        webView:(WKWebView*)webView;
+
+// Removes a specific message handler.
+- (void)removeScriptMessageHandlerForName:(NSString*)messageName
+                                  webView:(WKWebView*)webView;
+
+// Removes all message handlers for the given |webView|.
+- (void)removeAllScriptMessageHandlersForWebView:(WKWebView*)webView;
+
+@end
+
+#endif  // IOS_WEB_WEB_STATE_UI_CRW_WK_SCRIPT_MESSAGE_ROUTER_H_
diff --git a/ios/web/web_state/ui/crw_wk_script_message_router.mm b/ios/web/web_state/ui/crw_wk_script_message_router.mm
new file mode 100644
index 0000000..5699abd
--- /dev/null
+++ b/ios/web/web_state/ui/crw_wk_script_message_router.mm
@@ -0,0 +1,113 @@
+// 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.
+
+#import "ios/web/web_state/ui/crw_wk_script_message_router.h"
+
+#import "base/logging.h"
+#import "base/mac/scoped_nsobject.h"
+
+@interface CRWWKScriptMessageRouter ()<WKScriptMessageHandler>
+
+// Removes a specific message handler. Does nothing if handler does not exist.
+- (void)tryRemoveScriptMessageHandlerForName:(NSString*)messageName
+                                     webView:(WKWebView*)webView;
+
+@end
+
+@implementation CRWWKScriptMessageRouter {
+  // Two level map of registed message handlers. Keys are message names and
+  // values are more maps (where keys are web views and values are handlers).
+  base::scoped_nsobject<NSMutableDictionary> _handlers;
+  // Wrapped WKUserContentController.
+  base::scoped_nsobject<WKUserContentController> _userContentController;
+}
+
+#pragma mark -
+#pragma mark Interface
+
+- (WKUserContentController*)userContentController {
+  return _userContentController.get();
+}
+
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
+- (instancetype)initWithUserContentController:
+    (WKUserContentController*)userContentController {
+  DCHECK(userContentController);
+  if ((self = [super init])) {
+    _handlers.reset([[NSMutableDictionary alloc] init]);
+    _userContentController.reset([userContentController retain]);
+  }
+  return self;
+}
+
+- (void)setScriptMessageHandler:(void (^)(WKScriptMessage*))handler
+                           name:(NSString*)messageName
+                        webView:(WKWebView*)webView {
+  DCHECK(handler);
+  DCHECK(messageName);
+  DCHECK(webView);
+
+  NSMapTable* webViewToHandlerMap = [_handlers objectForKey:messageName];
+  if (!webViewToHandlerMap) {
+    webViewToHandlerMap =
+        [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsStrongMemory
+                              valueOptions:NSPointerFunctionsCopyIn];
+    [_handlers setObject:webViewToHandlerMap forKey:messageName];
+    [_userContentController addScriptMessageHandler:self name:messageName];
+  }
+  DCHECK(![webViewToHandlerMap objectForKey:webView]);
+  [webViewToHandlerMap setObject:handler forKey:webView];
+}
+
+- (void)removeScriptMessageHandlerForName:(NSString*)messageName
+                                  webView:(WKWebView*)webView {
+  DCHECK(messageName);
+  DCHECK(webView);
+  DCHECK([[_handlers objectForKey:messageName] objectForKey:webView]);
+  [self tryRemoveScriptMessageHandlerForName:messageName webView:webView];
+}
+
+- (void)removeAllScriptMessageHandlersForWebView:(WKWebView*)webView {
+  DCHECK(webView);
+  for (NSString* messageName in [_handlers allKeys]) {
+    [self tryRemoveScriptMessageHandlerForName:messageName webView:webView];
+  }
+}
+
+#pragma mark -
+#pragma mark WKScriptMessageHandler
+
+- (void)userContentController:(WKUserContentController*)userContentController
+      didReceiveScriptMessage:(WKScriptMessage*)message {
+  NSMapTable* webViewToHandlerMap = [_handlers objectForKey:message.name];
+  DCHECK(webViewToHandlerMap);
+  id handler = [webViewToHandlerMap objectForKey:message.webView];
+  if (handler) {
+    // Web process can send messages even if web view was reset and
+    // script message handler has been removed from the router.
+    ((void (^)(WKScriptMessage*))handler)(message);
+  }
+}
+
+#pragma mark -
+#pragma mark Implementation
+
+- (void)tryRemoveScriptMessageHandlerForName:(NSString*)messageName
+                                     webView:(WKWebView*)webView {
+  NSMapTable* webViewToHandlerMap = [_handlers objectForKey:messageName];
+  if (![webViewToHandlerMap objectForKey:webView])
+    return;
+  if (webViewToHandlerMap.count == 1) {
+    [_handlers removeObjectForKey:messageName];
+    [_userContentController removeScriptMessageHandlerForName:messageName];
+  } else {
+    [webViewToHandlerMap removeObjectForKey:webView];
+  }
+}
+
+@end
diff --git a/ios/web/web_state/ui/crw_wk_script_message_router_unittest.mm b/ios/web/web_state/ui/crw_wk_script_message_router_unittest.mm
new file mode 100644
index 0000000..a638b8e
--- /dev/null
+++ b/ios/web/web_state/ui/crw_wk_script_message_router_unittest.mm
@@ -0,0 +1,209 @@
+// 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.
+
+#import "ios/web/web_state/ui/crw_wk_script_message_router.h"
+
+#include "base/mac/scoped_block.h"
+#include "base/mac/scoped_nsobject.h"
+#include "ios/web/public/test/test_browser_state.h"
+#import "ios/web/public/test/test_web_client.h"
+#include "ios/web/public/test/web_test_util.h"
+#include "ios/web/test/web_test.h"
+#include "third_party/ocmock/OCMock/OCMock.h"
+#include "third_party/ocmock/gtest_support.h"
+
+namespace {
+
+// Returns WKScriptMessage mock.
+id GetScriptMessageMock(WKWebView* web_view, NSString* name) {
+  id result = [OCMockObject mockForClass:[WKScriptMessage class]];
+  [[[result stub] andReturn:web_view] webView];
+  [[[result stub] andReturn:name] name];
+  return result;
+}
+
+// Test fixture for CRWWKScriptMessageRouter.
+class CRWWKScriptMessageRouterTest : public web::WebTest {
+ protected:
+  void SetUp() override {
+    CR_TEST_REQUIRES_WK_WEB_VIEW();
+    web::SetWebClient(&web_client_);
+    // Mock WKUserContentController object.
+    controller_mock_.reset(
+        [[OCMockObject mockForClass:[WKUserContentController class]] retain]);
+    [controller_mock_ setExpectationOrderMatters:YES];
+
+    // Create testable CRWWKScriptMessageRouter.
+    router_.reset(static_cast<id<WKScriptMessageHandler>>(
+        [[CRWWKScriptMessageRouter alloc]
+            initWithUserContentController:controller_mock_]));
+
+    // Prepare test data.
+    handler1_.reset([^{
+    } copy]);
+    handler2_.reset([^{
+    } copy]);
+    handler3_.reset([^{
+    } copy]);
+    name1_.reset([@"name1" copy]);
+    name2_.reset([@"name2" copy]);
+    name3_.reset([@"name3" copy]);
+    web_view1_.reset(web::CreateWKWebView(CGRectZero, &browser_state_));
+    web_view2_.reset(web::CreateWKWebView(CGRectZero, &browser_state_));
+    web_view3_.reset(web::CreateWKWebView(CGRectZero, &browser_state_));
+  }
+  void TearDown() override {
+    EXPECT_OCMOCK_VERIFY(controller_mock_);
+    web::SetWebClient(nullptr);
+  }
+
+  // WKUserContentController mock used to create testable router.
+  base::scoped_nsobject<id> controller_mock_;
+
+  // CRWWKScriptMessageRouter set up for testing.
+  base::scoped_nsobject<id> router_;
+
+  // Tests data.
+  typedef void (^WKScriptMessageHandler)(WKScriptMessage*);
+  base::mac::ScopedBlock<WKScriptMessageHandler> handler1_;
+  base::mac::ScopedBlock<WKScriptMessageHandler> handler2_;
+  base::mac::ScopedBlock<WKScriptMessageHandler> handler3_;
+  base::scoped_nsobject<NSString> name1_;
+  base::scoped_nsobject<NSString> name2_;
+  base::scoped_nsobject<NSString> name3_;
+  base::scoped_nsobject<WKWebView> web_view1_;
+  base::scoped_nsobject<WKWebView> web_view2_;
+  base::scoped_nsobject<WKWebView> web_view3_;
+
+ private:
+  // WebClient and BrowserState for testing.
+  web::TestWebClient web_client_;
+  web::TestBrowserState browser_state_;
+};
+
+// Tests CRWWKScriptMessageRouter designated initializer.
+TEST_F(CRWWKScriptMessageRouterTest, Initialization) {
+  CR_TEST_REQUIRES_WK_WEB_VIEW();
+
+  EXPECT_TRUE(router_);
+}
+
+// Tests registration/deregistation of message handlers.
+TEST_F(CRWWKScriptMessageRouterTest, HandlerRegistration) {
+  CR_TEST_REQUIRES_WK_WEB_VIEW();
+
+  [[controller_mock_ expect] addScriptMessageHandler:router_ name:name1_];
+  [[controller_mock_ expect] addScriptMessageHandler:router_ name:name2_];
+
+  [[controller_mock_ expect] removeScriptMessageHandlerForName:name1_];
+  [[controller_mock_ expect] removeScriptMessageHandlerForName:name2_];
+
+  [router_ setScriptMessageHandler:handler1_ name:name1_ webView:web_view1_];
+  [router_ setScriptMessageHandler:handler2_ name:name2_ webView:web_view2_];
+  [router_ setScriptMessageHandler:handler3_ name:name2_ webView:web_view3_];
+
+  [router_ removeScriptMessageHandlerForName:name1_ webView:web_view1_];
+  [router_ removeScriptMessageHandlerForName:name2_ webView:web_view2_];
+  [router_ removeScriptMessageHandlerForName:name2_ webView:web_view3_];
+}
+
+// Tests registration of message handlers. Test ensures that
+// WKScriptMessageHandler is not removed if CRWWKScriptMessageRouter has valid
+// message handlers.
+TEST_F(CRWWKScriptMessageRouterTest, HandlerRegistrationLeak) {
+  CR_TEST_REQUIRES_WK_WEB_VIEW();
+
+  [[controller_mock_ expect] addScriptMessageHandler:router_ name:name1_];
+
+  // -removeScriptMessageHandlerForName must not be called.
+
+  [router_ setScriptMessageHandler:handler1_ name:name1_ webView:web_view1_];
+  [router_ setScriptMessageHandler:handler2_ name:name1_ webView:web_view2_];
+
+  [router_ removeScriptMessageHandlerForName:name1_ webView:web_view1_];
+}
+
+// Tests deregistation of all message handlers.
+TEST_F(CRWWKScriptMessageRouterTest, RemoveAllHandlers) {
+  CR_TEST_REQUIRES_WK_WEB_VIEW();
+
+  [[controller_mock_ expect] addScriptMessageHandler:router_ name:name1_];
+  [[controller_mock_ expect] addScriptMessageHandler:router_ name:name2_];
+
+  [[controller_mock_ expect] removeScriptMessageHandlerForName:name2_];
+  [[controller_mock_ expect] removeScriptMessageHandlerForName:name1_];
+
+  [router_ setScriptMessageHandler:handler1_ name:name1_ webView:web_view1_];
+  [router_ setScriptMessageHandler:handler2_ name:name2_ webView:web_view1_];
+  [router_ setScriptMessageHandler:handler3_ name:name1_ webView:web_view2_];
+
+  [router_ removeAllScriptMessageHandlersForWebView:web_view1_];
+  [router_ removeAllScriptMessageHandlersForWebView:web_view2_];
+}
+
+// Tests deregistation of all message handlers. Test ensures that
+// WKScriptMessageHandler is not removed if CRWWKScriptMessageRouter has valid
+// message handlers.
+TEST_F(CRWWKScriptMessageRouterTest, RemoveAllHandlersLeak) {
+  CR_TEST_REQUIRES_WK_WEB_VIEW();
+
+  [[controller_mock_ expect] addScriptMessageHandler:router_ name:name1_];
+  [[controller_mock_ expect] addScriptMessageHandler:router_ name:name2_];
+  [[controller_mock_ expect] addScriptMessageHandler:router_ name:name3_];
+
+  [[controller_mock_ expect] removeScriptMessageHandlerForName:name2_];
+  // -removeScriptMessageHandlerForName:name1_ must not be called.
+
+  [router_ setScriptMessageHandler:handler1_ name:name1_ webView:web_view1_];
+  [router_ setScriptMessageHandler:handler2_ name:name2_ webView:web_view1_];
+  [router_ setScriptMessageHandler:handler2_ name:name3_ webView:web_view2_];
+  [router_ setScriptMessageHandler:handler3_ name:name1_ webView:web_view2_];
+
+  [router_ removeAllScriptMessageHandlersForWebView:web_view1_];
+}
+
+// Tests proper routing of WKScriptMessage object depending on message name and
+// web view.
+TEST_F(CRWWKScriptMessageRouterTest, Routing) {
+  CR_TEST_REQUIRES_WK_WEB_VIEW();
+
+  // It's expected that messages handlers will be called once and in order.
+  __block NSInteger last_called_handler = 0;
+  id message1 = GetScriptMessageMock(web_view1_, name1_);
+  id handler1 = ^(WKScriptMessage* message) {
+    EXPECT_EQ(0, last_called_handler);
+    EXPECT_EQ(message1, message);
+    last_called_handler = 1;
+  };
+  id message2 = GetScriptMessageMock(web_view2_, name2_);
+  id handler2 = ^(WKScriptMessage* message) {
+    EXPECT_EQ(1, last_called_handler);
+    EXPECT_EQ(message2, message);
+    last_called_handler = 2;
+  };
+  id message3 = GetScriptMessageMock(web_view3_, name2_);
+  id handler3 = ^(WKScriptMessage* message) {
+    EXPECT_EQ(2, last_called_handler);
+    EXPECT_EQ(message3, message);
+    last_called_handler = 3;
+  };
+
+  [[controller_mock_ expect] addScriptMessageHandler:router_ name:name1_];
+  [[controller_mock_ expect] addScriptMessageHandler:router_ name:name2_];
+
+  [router_ setScriptMessageHandler:handler1 name:name1_ webView:web_view1_];
+  [router_ setScriptMessageHandler:handler2 name:name2_ webView:web_view2_];
+  [router_ setScriptMessageHandler:handler3 name:name2_ webView:web_view3_];
+
+  [router_ userContentController:controller_mock_
+         didReceiveScriptMessage:message1];
+  [router_ userContentController:controller_mock_
+         didReceiveScriptMessage:message2];
+  [router_ userContentController:controller_mock_
+         didReceiveScriptMessage:message3];
+
+  EXPECT_EQ(3, last_called_handler);
+}
+
+}  // namespace
diff --git a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
index e5c88664..db9dc92 100644
--- a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
+++ b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
@@ -32,8 +32,8 @@
 #import "ios/web/web_state/error_translation_util.h"
 #include "ios/web/web_state/frame_info.h"
 #import "ios/web/web_state/js/crw_js_window_id_manager.h"
-#import "ios/web/web_state/js/page_script_util.h"
 #import "ios/web/web_state/ui/crw_web_controller+protected.h"
+#import "ios/web/web_state/ui/crw_wk_script_message_router.h"
 #import "ios/web/web_state/ui/crw_wk_web_view_crash_detector.h"
 #import "ios/web/web_state/ui/web_view_js_utils.h"
 #import "ios/web/web_state/ui/wk_back_forward_list_item_holder.h"
@@ -82,9 +82,7 @@
 
 }  // namespace
 
-@interface CRWWKWebViewWebController () <WKNavigationDelegate,
-                                         WKScriptMessageHandler,
-                                         WKUIDelegate> {
+@interface CRWWKWebViewWebController ()<WKNavigationDelegate, WKUIDelegate> {
   // The WKWebView managed by this instance.
   base::scoped_nsobject<WKWebView> _wkWebView;
 
@@ -264,9 +262,8 @@
 // _documentURL, and informs the superclass of the change.
 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)URL;
 
-// Returns new autoreleased instance of WKUserContentController which has
-// early page script.
-- (WKUserContentController*)createUserContentController;
+// Called when web controller receives a new message from the web page.
+- (void)didReceiveScriptMessage:(WKScriptMessage*)message;
 
 // Attempts to handle a script message. Returns YES on success, NO otherwise.
 - (BOOL)respondToWKScriptMessage:(WKScriptMessage*)scriptMessage;
@@ -643,11 +640,6 @@
 
 - (void)ensureWebViewCreatedWithConfiguration:(WKWebViewConfiguration*)config {
   if (!_wkWebView) {
-    // Use a separate userContentController for each web view.
-    // WKUserContentController does not allow adding multiple script message
-    // handlers for the same name, hence userContentController can't be shared
-    // between all web views.
-    config.userContentController = [self createUserContentController];
     [self setWebView:[self createWebViewWithConfiguration:config]];
     // Notify super class about created web view. -webViewDidChange is not
     // called from -setWebView:scriptMessageRouter: as the latter used in unit
@@ -667,10 +659,13 @@
   DCHECK_NE(_wkWebView.get(), webView);
 
   // Unwind the old web view.
-  WKUserContentController* oldContentController =
-      [[_wkWebView configuration] userContentController];
-  [oldContentController removeScriptMessageHandlerForName:kScriptMessageName];
-  [oldContentController removeScriptMessageHandlerForName:kScriptImmediateName];
+  // TODO(eugenebut): Remove CRWWKScriptMessageRouter once crbug.com/543374 is
+  // fixed.
+  CRWWKScriptMessageRouter* messageRouter =
+      [self webViewConfigurationProvider].GetScriptMessageRouter();
+  if (_wkWebView) {
+    [messageRouter removeAllScriptMessageHandlersForWebView:_wkWebView];
+  }
   [_wkWebView setNavigationDelegate:nil];
   [_wkWebView setUIDelegate:nil];
   for (NSString* keyPath in self.wkWebViewObservers) {
@@ -681,10 +676,18 @@
   _wkWebView.reset([webView retain]);
 
   // Set up the new web view.
-  WKUserContentController* newContentController =
-      [[_wkWebView configuration] userContentController];
-  [newContentController addScriptMessageHandler:self name:kScriptMessageName];
-  [newContentController addScriptMessageHandler:self name:kScriptImmediateName];
+  if (webView) {
+    base::WeakNSObject<CRWWKWebViewWebController> weakSelf(self);
+    void (^messageHandler)(WKScriptMessage*) = ^(WKScriptMessage* message) {
+      [weakSelf didReceiveScriptMessage:message];
+    };
+    [messageRouter setScriptMessageHandler:messageHandler
+                                      name:kScriptMessageName
+                                   webView:webView];
+    [messageRouter setScriptMessageHandler:messageHandler
+                                      name:kScriptImmediateName
+                                   webView:webView];
+  }
   [_wkWebView setNavigationDelegate:self];
   [_wkWebView setUIDelegate:self];
   for (NSString* keyPath in self.wkWebViewObservers) {
@@ -938,19 +941,7 @@
   }
 }
 
-- (WKUserContentController*)createUserContentController {
-  WKUserContentController* result =
-      [[[WKUserContentController alloc] init] autorelease];
-  base::scoped_nsobject<WKUserScript> script([[WKUserScript alloc]
-        initWithSource:web::GetEarlyPageScript(web::WK_WEB_VIEW_TYPE)
-         injectionTime:WKUserScriptInjectionTimeAtDocumentStart
-      forMainFrameOnly:YES]);
-  [result addUserScript:script];
-  return result;
-}
-
-- (void)userContentController:(WKUserContentController*)userContentController
-      didReceiveScriptMessage:(WKScriptMessage*)message {
+- (void)didReceiveScriptMessage:(WKScriptMessage*)message {
   // Broken out into separate method to catch errors.
   // TODO(jyquinn): Evaluate whether this is necessary for WKWebView.
   if (![self respondToWKScriptMessage:message]) {
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider.h b/ios/web/web_state/ui/wk_web_view_configuration_provider.h
index 32a4130d..1059e135 100644
--- a/ios/web/web_state/ui/wk_web_view_configuration_provider.h
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider.h
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "base/supports_user_data.h"
 
+@class CRWWKScriptMessageRouter;
 @class WKWebViewConfiguration;
 
 namespace web {
@@ -16,8 +17,9 @@
 class BrowserState;
 
 // A provider class associated with a single web::BrowserState object. Manages
-// the lifetime and performs setup of WKWebViewConfiguration instance.
-// Not threadsafe. Must be used only on the main thread.
+// the lifetime and performs setup of WKWebViewConfiguration and
+// CRWWKScriptMessageRouter instances. Not threadsafe. Must be used only on the
+// main thread.
 class WKWebViewConfigurationProvider : public base::SupportsUserData::Data {
  public:
   // Returns a provider for the given |browser_state|. Lazily attaches one if it
@@ -32,9 +34,14 @@
   // Callers must not retain the returned object.
   WKWebViewConfiguration* GetWebViewConfiguration();
 
-  // Purges config object if it exists. When this method is called config and
-  // config's process pool must not be retained by anyone (this will be enforced
-  // in debug builds).
+  // Returns CRWWKScriptMessafeRouter associated with WKWebViewConfiguration.
+  // Lazily creates the router. Callers must not retain the returned object
+  // (this will be enforced in debug builds).
+  CRWWKScriptMessageRouter* GetScriptMessageRouter();
+
+  // Purges config and router objects if they exist. When this method is called
+  // config and config's process pool must not be retained by anyone (this will
+  // be enforced in debug builds).
   void Purge();
 
  private:
@@ -43,6 +50,7 @@
   ~WKWebViewConfigurationProvider() override;
 
   base::scoped_nsobject<WKWebViewConfiguration> configuration_;
+  base::scoped_nsobject<CRWWKScriptMessageRouter> router_;
   // Result of |web::BrowserState::IsOffTheRecord| call.
   bool is_off_the_record_;
 
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider.mm b/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
index d50a625..693b5184 100644
--- a/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
@@ -14,6 +14,7 @@
 #import "ios/web/alloc_with_zone_interceptor.h"
 #include "ios/web/public/browser_state.h"
 #import "ios/web/web_state/js/page_script_util.h"
+#import "ios/web/web_state/ui/crw_wk_script_message_router.h"
 #import "ios/web/web_state/web_view_internal_creation_util.h"
 
 #if !defined(NDEBUG)
@@ -162,15 +163,30 @@
   return [[configuration_ copy] autorelease];
 }
 
+CRWWKScriptMessageRouter*
+WKWebViewConfigurationProvider::GetScriptMessageRouter() {
+  DCHECK([NSThread isMainThread]);
+  if (!router_) {
+    WKUserContentController* userContentController =
+        [GetWebViewConfiguration() userContentController];
+    router_.reset([[CRWWKScriptMessageRouter alloc]
+        initWithUserContentController:userContentController]);
+  }
+  return router_;
+}
+
 void WKWebViewConfigurationProvider::Purge() {
   DCHECK([NSThread isMainThread]);
 #if !defined(NDEBUG) || !defined(DCHECK_ALWAYS_ON)  // Matches DCHECK_IS_ON.
   base::WeakNSObject<id> weak_configuration(configuration_);
+  base::WeakNSObject<id> weak_router(router_);
   base::WeakNSObject<id> weak_process_pool([configuration_ processPool]);
 #endif  // !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
   configuration_.reset();
-  // Make sure that no one retains configuration and processPool.
+  router_.reset();
+  // Make sure that no one retains configuration, router, processPool.
   DCHECK(!weak_configuration);
+  DCHECK(!weak_router);
   // TODO(shreyasv): Enable this DCHECK (crbug.com/522672).
   // DCHECK(!weak_process_pool);
 }
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm b/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm
index a75bc03..7a1e099 100644
--- a/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm
@@ -12,6 +12,7 @@
 #include "ios/web/public/test/web_test_util.h"
 #include "ios/web/public/web_client.h"
 #import "ios/web/web_state/js/page_script_util.h"
+#import "ios/web/web_state/ui/crw_wk_script_message_router.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
@@ -131,19 +132,33 @@
             provider.GetWebViewConfiguration().userContentController);
 }
 
-// Tests that configuration is deallocated after |Purge| call.
+// Tests that script message router is bound to correct user content controller.
+TEST_F(WKWebViewConfigurationProviderTest, ScriptMessageRouter) {
+  CR_TEST_REQUIRES_WK_WEB_VIEW();
+
+  ASSERT_TRUE(GetProvider().GetWebViewConfiguration().userContentController);
+  EXPECT_EQ(GetProvider().GetWebViewConfiguration().userContentController,
+            GetProvider().GetScriptMessageRouter().userContentController);
+}
+
+// Tests that both configuration and script message router are deallocated after
+// |Purge| call.
 TEST_F(WKWebViewConfigurationProviderTest, Purge) {
   CR_TEST_REQUIRES_WK_WEB_VIEW();
 
   base::WeakNSObject<id> config;
+  base::WeakNSObject<id> router;
   @autoreleasepool {  // Make sure that resulting copy is deallocated.
     config.reset(GetProvider().GetWebViewConfiguration());
+    router.reset(GetProvider().GetScriptMessageRouter());
     ASSERT_TRUE(config);
+    ASSERT_TRUE(router);
   }
 
-  // No configuration after |Purge| call.
+  // No configuration and router after |Purge| call.
   GetProvider().Purge();
   EXPECT_FALSE(config);
+  EXPECT_FALSE(router);
 }
 
 // Tests that configuration's userContentController has only one script with the
diff --git a/mandoline/ui/desktop_ui/browser_manager.cc b/mandoline/ui/desktop_ui/browser_manager.cc
index 54d2558..bef4dd5 100644
--- a/mandoline/ui/desktop_ui/browser_manager.cc
+++ b/mandoline/ui/desktop_ui/browser_manager.cc
@@ -5,8 +5,8 @@
 #include "mandoline/ui/desktop_ui/browser_manager.h"
 
 #include "base/command_line.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_observer.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_observer.h"
 #include "mandoline/ui/desktop_ui/browser_window.h"
 
 namespace mandoline {
diff --git a/mandoline/ui/desktop_ui/browser_window.cc b/mandoline/ui/desktop_ui/browser_window.cc
index 333728e..363320e 100644
--- a/mandoline/ui/desktop_ui/browser_window.cc
+++ b/mandoline/ui/desktop_ui/browser_window.cc
@@ -8,8 +8,8 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
-#include "components/mus/public/cpp/scoped_view_ptr.h"
-#include "components/mus/public/cpp/view_tree_host_factory.h"
+#include "components/mus/public/cpp/scoped_window_ptr.h"
+#include "components/mus/public/cpp/window_tree_host_factory.h"
 #include "mandoline/ui/desktop_ui/browser_commands.h"
 #include "mandoline/ui/desktop_ui/browser_manager.h"
 #include "mandoline/ui/desktop_ui/find_bar_view.h"
@@ -84,7 +84,7 @@
       web_view_(this) {
   mojo::ViewTreeHostClientPtr host_client;
   host_client_binding_.Bind(GetProxy(&host_client));
-  mus::CreateViewTreeHost(host_factory, host_client.Pass(), this, &host_);
+  mus::CreateWindowTreeHost(host_factory, host_client.Pass(), this, &host_);
 }
 
 void BrowserWindow::LoadURL(const GURL& url) {
@@ -107,7 +107,7 @@
 
 void BrowserWindow::Close() {
   if (root_)
-    mus::ScopedViewPtr::DeleteViewOrViewManager(root_);
+    mus::ScopedWindowPtr::DeleteWindowOrWindowManager(root_);
   else
     delete this;
 }
@@ -154,7 +154,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserWindow, mus::ViewTreeDelegate implementation:
 
-void BrowserWindow::OnEmbed(mus::View* root) {
+void BrowserWindow::OnEmbed(mus::Window* root) {
   // BrowserWindow does not support being embedded more than once.
   CHECK(!root_);
 
@@ -165,7 +165,7 @@
 
   host_->SetTitle("Mandoline");
 
-  content_ = root_->connection()->CreateView();
+  content_ = root_->connection()->CreateWindow();
   Init(root_);
 
   host_->SetSize(mojo::Size::From(gfx::Size(1280, 800)));
@@ -211,7 +211,7 @@
   }
 }
 
-void BrowserWindow::OnConnectionLost(mus::ViewTreeConnection* connection) {
+void BrowserWindow::OnConnectionLost(mus::WindowTreeConnection* connection) {
   root_ = nullptr;
   delete this;
 }
@@ -369,14 +369,13 @@
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserWindow, private:
 
-void BrowserWindow::Init(mus::View* root) {
+void BrowserWindow::Init(mus::Window* root) {
   DCHECK_GT(root->viewport_metrics().device_pixel_ratio, 0);
   if (!aura_init_)
-    aura_init_.reset(
-        new views::AuraInit(root, app_->shell(), "mandoline_ui.pak"));
+    aura_init_.reset(new views::AuraInit(app_, "mandoline_ui.pak", root));
 
   root_ = root;
-  omnibox_view_ = root_->connection()->CreateView();
+  omnibox_view_ = root_->connection()->CreateWindow();
   root_->AddChild(omnibox_view_);
 
   views::WidgetDelegateView* widget_delegate = new views::WidgetDelegateView;
diff --git a/mandoline/ui/desktop_ui/browser_window.h b/mandoline/ui/desktop_ui/browser_window.h
index 0d487a4..2824c42 100644
--- a/mandoline/ui/desktop_ui/browser_window.h
+++ b/mandoline/ui/desktop_ui/browser_window.h
@@ -5,8 +5,8 @@
 #ifndef MANDOLINE_UI_DESKTOP_UI_BROWSER_WINDOW_H_
 #define MANDOLINE_UI_DESKTOP_UI_BROWSER_WINDOW_H_
 
-#include "components/mus/public/cpp/view_tree_connection.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
 #include "components/mus/public/interfaces/view_tree_host.mojom.h"
 #include "components/web_view/public/cpp/web_view.h"
 #include "components/web_view/public/interfaces/web_view.mojom.h"
@@ -32,7 +32,7 @@
 class ProgressView;
 class ToolbarView;
 
-class BrowserWindow : public mus::ViewTreeDelegate,
+class BrowserWindow : public mus::WindowTreeDelegate,
                       public mojo::ViewTreeHostClient,
                       public web_view::mojom::WebViewClient,
                       public ViewEmbedder,
@@ -57,9 +57,9 @@
 
   float DIPSToPixels(float value) const;
 
-  // Overridden from mus::ViewTreeDelegate:
-  void OnEmbed(mus::View* root) override;
-  void OnConnectionLost(mus::ViewTreeConnection* connection) override;
+  // Overridden from mus::WindowTreeDelegate:
+  void OnEmbed(mus::Window* root) override;
+  void OnConnectionLost(mus::WindowTreeConnection* connection) override;
 
   // Overridden from ViewTreeHostClient:
   void OnAccelerator(uint32_t id, mojo::EventPtr event) override;
@@ -93,7 +93,7 @@
   void OnDoFind(const std::string& find, bool forward) override;
   void OnHideFindBar() override;
 
-  void Init(mus::View* root);
+  void Init(mus::Window* root);
   void EmbedOmnibox();
 
   mojo::ApplicationImpl* app_;
@@ -104,9 +104,9 @@
   ToolbarView* toolbar_view_;
   ProgressView* progress_bar_;
   FindBarView* find_bar_view_;
-  mus::View* root_;
-  mus::View* content_;
-  mus::View* omnibox_view_;
+  mus::Window* root_;
+  mus::Window* content_;
+  mus::Window* omnibox_view_;
 
   mojo::WeakBindingSet<ViewEmbedder> view_embedder_bindings_;
 
diff --git a/mandoline/ui/omnibox/omnibox_application.cc b/mandoline/ui/omnibox/omnibox_application.cc
index 2579005..3c5491d 100644
--- a/mandoline/ui/omnibox/omnibox_application.cc
+++ b/mandoline/ui/omnibox/omnibox_application.cc
@@ -6,9 +6,9 @@
 
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
 #include "components/url_formatter/url_fixer.h"
 #include "mandoline/ui/desktop_ui/public/interfaces/view_embedder.mojom.h"
 #include "mojo/application/public/cpp/application_impl.h"
@@ -27,7 +27,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // OmniboxImpl
 
-class OmniboxImpl : public mus::ViewTreeDelegate,
+class OmniboxImpl : public mus::WindowTreeDelegate,
                     public views::LayoutManager,
                     public views::TextfieldController,
                     public Omnibox {
@@ -38,9 +38,9 @@
   ~OmniboxImpl() override;
 
  private:
-  // Overridden from mus::ViewTreeDelegate:
-  void OnEmbed(mus::View* root) override;
-  void OnConnectionLost(mus::ViewTreeConnection* connection) override;
+  // Overridden from mus::WindowTreeDelegate:
+  void OnEmbed(mus::Window* root) override;
+  void OnConnectionLost(mus::WindowTreeConnection* connection) override;
 
   // Overridden from views::LayoutManager:
   gfx::Size GetPreferredSize(const views::View* view) const override;
@@ -60,7 +60,7 @@
 
   scoped_ptr<views::AuraInit> aura_init_;
   mojo::ApplicationImpl* app_;
-  mus::View* root_;
+  mus::Window* root_;
   mojo::String url_;
   views::Textfield* edit_;
   mojo::Binding<Omnibox> binding_;
@@ -111,14 +111,13 @@
 OmniboxImpl::~OmniboxImpl() {}
 
 ////////////////////////////////////////////////////////////////////////////////
-// OmniboxImpl, mus::ViewTreeDelegate implementation:
+// OmniboxImpl, mus::WindowTreeDelegate implementation:
 
-void OmniboxImpl::OnEmbed(mus::View* root) {
+void OmniboxImpl::OnEmbed(mus::Window* root) {
   root_ = root;
 
   if (!aura_init_.get()) {
-    aura_init_.reset(
-        new views::AuraInit(root, app_->shell(), "mandoline_ui.pak"));
+    aura_init_.reset(new views::AuraInit(app_, "mandoline_ui.pak", root_));
     edit_ = new views::Textfield;
     edit_->set_controller(this);
     edit_->SetTextInputType(ui::TEXT_INPUT_TYPE_URL);
@@ -150,7 +149,7 @@
   ShowWindow();
 }
 
-void OmniboxImpl::OnConnectionLost(mus::ViewTreeConnection* connection) {
+void OmniboxImpl::OnConnectionLost(mus::WindowTreeConnection* connection) {
   root_ = nullptr;
 }
 
@@ -192,9 +191,9 @@
 
 void OmniboxImpl::GetViewTreeClient(
     mojo::InterfaceRequest<mojo::ViewTreeClient> request) {
-  mus::ViewTreeConnection::Create(
+  mus::WindowTreeConnection::Create(
       this, request.Pass(),
-      mus::ViewTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
+      mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
 }
 
 void OmniboxImpl::ShowForURL(const mojo::String& url) {
diff --git a/mandoline/ui/phone_ui/phone_browser_application_delegate.cc b/mandoline/ui/phone_ui/phone_browser_application_delegate.cc
index d2ac75b..ef3758d 100644
--- a/mandoline/ui/phone_ui/phone_browser_application_delegate.cc
+++ b/mandoline/ui/phone_ui/phone_browser_application_delegate.cc
@@ -5,9 +5,9 @@
 #include "mandoline/ui/phone_ui/phone_browser_application_delegate.h"
 
 #include "base/command_line.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
-#include "components/mus/public/cpp/view_tree_host_factory.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_host_factory.h"
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
@@ -47,7 +47,7 @@
       break;
     }
   }
-  mus::CreateSingleViewTreeHost(app_, this, &host_);
+  mus::CreateSingleWindowTreeHost(app_, this, &host_);
 }
 
 bool PhoneBrowserApplicationDelegate::ConfigureIncomingConnection(
@@ -66,12 +66,12 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// PhoneBrowserApplicationDelegate, mus::ViewTreeDelegate implementation:
+// PhoneBrowserApplicationDelegate, mus::WindowTreeDelegate implementation:
 
-void PhoneBrowserApplicationDelegate::OnEmbed(mus::View* root) {
+void PhoneBrowserApplicationDelegate::OnEmbed(mus::Window* root) {
   CHECK(!root_);
   root_ = root;
-  content_ = root->connection()->CreateView();
+  content_ = root->connection()->CreateWindow();
   root->AddChild(content_);
   content_->SetBounds(root->bounds());
   content_->SetVisible(true);
@@ -83,13 +83,13 @@
 }
 
 void PhoneBrowserApplicationDelegate::OnConnectionLost(
-    mus::ViewTreeConnection* connection) {}
+    mus::WindowTreeConnection* connection) {}
 
 ////////////////////////////////////////////////////////////////////////////////
-// PhoneBrowserApplicationDelegate, mus::ViewObserver implementation:
+// PhoneBrowserApplicationDelegate, mus::WindowObserver implementation:
 
-void PhoneBrowserApplicationDelegate::OnViewBoundsChanged(
-    mus::View* view,
+void PhoneBrowserApplicationDelegate::OnWindowBoundsChanged(
+    mus::Window* view,
     const mojo::Rect& old_bounds,
     const mojo::Rect& new_bounds) {
   CHECK_EQ(view, root_);
diff --git a/mandoline/ui/phone_ui/phone_browser_application_delegate.h b/mandoline/ui/phone_ui/phone_browser_application_delegate.h
index f310259..e21c225 100644
--- a/mandoline/ui/phone_ui/phone_browser_application_delegate.h
+++ b/mandoline/ui/phone_ui/phone_browser_application_delegate.h
@@ -7,8 +7,8 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
-#include "components/mus/public/cpp/view_observer.h"
-#include "components/mus/public/cpp/view_tree_delegate.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
 #include "components/mus/public/interfaces/view_tree_host.mojom.h"
 #include "components/web_view/public/cpp/web_view.h"
 #include "components/web_view/public/interfaces/web_view.mojom.h"
@@ -27,8 +27,8 @@
 class PhoneBrowserApplicationDelegate
     : public mojo::ApplicationDelegate,
       public LaunchHandler,
-      public mus::ViewTreeDelegate,
-      public mus::ViewObserver,
+      public mus::WindowTreeDelegate,
+      public mus::WindowObserver,
       public web_view::mojom::WebViewClient,
       public mojo::InterfaceFactory<LaunchHandler> {
  public:
@@ -44,14 +44,14 @@
   // Overridden from LaunchHandler:
   void LaunchURL(const mojo::String& url) override;
 
-  // Overridden from mus::ViewTreeDelegate:
-  void OnEmbed(mus::View* root) override;
-  void OnConnectionLost(mus::ViewTreeConnection* connection) override;
+  // Overridden from mus::WindowTreeDelegate:
+  void OnEmbed(mus::Window* root) override;
+  void OnConnectionLost(mus::WindowTreeConnection* connection) override;
 
-  // Overridden from mus::ViewObserver:
-  void OnViewBoundsChanged(mus::View* view,
-                           const mojo::Rect& old_bounds,
-                           const mojo::Rect& new_bounds) override;
+  // Overridden from mus::WindowObserver:
+  void OnWindowBoundsChanged(mus::Window* view,
+                             const mojo::Rect& old_bounds,
+                             const mojo::Rect& new_bounds) override;
 
   // Overridden from web_view::mojom::WebViewClient:
   void TopLevelNavigateRequest(mojo::URLRequestPtr request) override;
@@ -73,8 +73,8 @@
   mojo::ApplicationImpl* app_;
   mojo::ViewTreeHostPtr host_;
 
-  mus::View* root_;
-  mus::View* content_;
+  mus::Window* root_;
+  mus::Window* content_;
   web_view::WebView web_view_;
 
   mojo::String default_url_;
diff --git a/media/BUILD.gn b/media/BUILD.gn
index aae2154..76c0fac 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -56,6 +56,12 @@
       "/DELAYLOAD:mfreadwrite.dll",
     ]
   }
+  if (media_use_ffmpeg && is_android) {
+    defines += [
+      "ENABLE_MEDIA_PIPELINE_ON_ANDROID",
+      "DISABLE_FFMPEG_VIDEO_DECODERS",
+    ]
+  }
 }
 
 if (use_ozone) {
@@ -364,6 +370,14 @@
   }
 
   if (is_android) {
+    # On Android, FFmpeg is built without video decoders. We only
+    # support hardware video decoding.
+    if (media_use_ffmpeg) {
+      sources -= [
+        "filters/ffmpeg_video_decoder.cc",
+        "filters/ffmpeg_video_decoder.h",
+      ]
+    }
     sources += [
       "capture/video/android/video_capture_device_android.cc",
       "capture/video/android/video_capture_device_android.h",
@@ -376,7 +390,9 @@
       "//media/base/android:video_capture_jni_headers",
     ]
     allow_circular_includes_from = [ "//media/base/android" ]
-  } else {
+  }
+
+  if (!is_android || media_use_ffmpeg) {
     sources += [
       "filters/opus_audio_decoder.cc",
       "filters/opus_audio_decoder.h",
@@ -518,6 +534,7 @@
   public_deps = [
     "//media/base",
     "//media/audio",
+    "//third_party/opus",
   ]
 
   deps += [
@@ -666,13 +683,20 @@
     sources += [
       "ffmpeg/ffmpeg_common_unittest.cc",
       "filters/audio_decoder_unittest.cc",
-      "filters/audio_file_reader_unittest.cc",
-      "filters/blocking_url_protocol_unittest.cc",
       "filters/ffmpeg_demuxer_unittest.cc",
       "filters/ffmpeg_glue_unittest.cc",
-      "filters/ffmpeg_video_decoder_unittest.cc",
-      "filters/in_memory_url_protocol_unittest.cc",
     ]
+
+    # Even if FFmpeg is enabled we do not want these files on Android.
+    # TODO(watk): Refactor tests that could be made to run on Android.
+    if (!is_android) {
+      sources += [
+        "filters/audio_file_reader_unittest.cc",
+        "filters/blocking_url_protocol_unittest.cc",
+        "filters/ffmpeg_video_decoder_unittest.cc",
+        "filters/in_memory_url_protocol_unittest.cc",
+      ]
+    }
   }
 
   if (media_use_libwebm) {
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index 3565553..691e130 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -220,13 +220,17 @@
 
   if (media_use_ffmpeg) {
     sources += [
-      "audio_video_metadata_extractor.cc",
-      "audio_video_metadata_extractor.h",
       "container_names.cc",
       "container_names.h",
-      "media_file_checker.cc",
-      "media_file_checker.h",
     ]
+    if (!is_android) {
+      sources += [
+        "audio_video_metadata_extractor.cc",
+        "audio_video_metadata_extractor.h",
+        "media_file_checker.cc",
+        "media_file_checker.h",
+      ]
+    }
 
     deps += [ "//third_party/ffmpeg" ]
   }
@@ -432,7 +436,9 @@
     "//testing/gtest",
   ]
 
-  if (media_use_ffmpeg) {
+  # Even if FFmpeg is enabled on Android we don't want these.
+  # TODO(watk): Refactor tests that could be made to run on Android.
+  if (media_use_ffmpeg && !is_android) {
     sources += [
       "audio_video_metadata_extractor_unittest.cc",
       "media_file_checker_unittest.cc",
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn
index a805c42..eb0661b 100644
--- a/media/blink/BUILD.gn
+++ b/media/blink/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//media/media_options.gni")
 import("//testing/test.gni")
 
 component("blink") {
@@ -40,8 +41,6 @@
     "cdm_result_promise_helper.h",
     "cdm_session_adapter.cc",
     "cdm_session_adapter.h",
-    "encrypted_media_player_support.cc",
-    "encrypted_media_player_support.h",
     "key_system_config_selector.cc",
     "key_system_config_selector.h",
     "new_session_cdm_result_promise.cc",
@@ -63,8 +62,6 @@
     "webinbandtexttrack_impl.cc",
     "webinbandtexttrack_impl.h",
     "webmediaplayer_delegate.h",
-    "webmediaplayer_impl.cc",
-    "webmediaplayer_impl.h",
     "webmediaplayer_params.cc",
     "webmediaplayer_params.h",
     "webmediaplayer_util.cc",
@@ -75,8 +72,8 @@
     "websourcebuffer_impl.h",
   ]
 
-  if (is_android) {
-    sources -= [
+  if (media_use_ffmpeg || !is_android) {
+    sources += [
       "encrypted_media_player_support.cc",
       "encrypted_media_player_support.h",
       "webmediaplayer_impl.cc",
diff --git a/media/cdm/ppapi/BUILD.gn b/media/cdm/ppapi/BUILD.gn
index 1fdebd1..b6b2dec 100644
--- a/media/cdm/ppapi/BUILD.gn
+++ b/media/cdm/ppapi/BUILD.gn
@@ -5,9 +5,7 @@
 import("//build/config/features.gni")
 import("//chrome/version.gni")  # TODO layering violation!
 import("//media/cdm/ppapi/cdm_adapter.gni")
-
-# Android doesn't use ffmpeg.
-use_ffmpeg = !is_android
+import("//media/media_options.gni")
 
 # The GYP version supports build flags "use_fake_video_decoder" and
 # "use_vpx". These should be added here if necessary but its not clear if
@@ -36,7 +34,7 @@
     "//url",
   ]
 
-  if (use_ffmpeg) {
+  if (media_use_ffmpeg) {
     sources += [
       "external_clear_key/ffmpeg_cdm_audio_decoder.cc",
       "external_clear_key/ffmpeg_cdm_audio_decoder.h",
diff --git a/media/test/BUILD.gn b/media/test/BUILD.gn
index b2b5002..c4f4d4d 100644
--- a/media/test/BUILD.gn
+++ b/media/test/BUILD.gn
@@ -7,7 +7,9 @@
 source_set("pipeline_integration_test_base") {
   testonly = true
 
-  if (media_use_ffmpeg) {
+  # Even if FFmpeg is enabled on Android we don't want these.
+  # TODO(watk): Refactor tests that could be made to run on Android.
+  if (media_use_ffmpeg && !is_android) {
     sources = [
       "pipeline_integration_test_base.cc",
       "pipeline_integration_test_base.h",
@@ -28,7 +30,7 @@
 source_set("pipeline_integration_tests") {
   testonly = true
 
-  if (media_use_ffmpeg) {
+  if (media_use_ffmpeg && !is_android) {
     sources = [
       "pipeline_integration_test.cc",
     ]
@@ -56,7 +58,7 @@
 source_set("pipeline_integration_perftests") {
   testonly = true
 
-  if (media_use_ffmpeg) {
+  if (media_use_ffmpeg && !is_android) {
     sources = [
       "pipeline_integration_perftest.cc",
     ]
@@ -79,7 +81,7 @@
   source_set("mojo_pipeline_integration_tests") {
     testonly = true
 
-    if (media_use_ffmpeg) {
+    if (media_use_ffmpeg && !is_android) {
       sources = [
         "pipeline_integration_test.cc",
       ]
diff --git a/mojo/converters/network/BUILD.gn b/mojo/converters/network/BUILD.gn
new file mode 100644
index 0000000..17308b07
--- /dev/null
+++ b/mojo/converters/network/BUILD.gn
@@ -0,0 +1,13 @@
+# 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.
+
+source_set("network") {
+  public_deps = [
+    "//mojo/services/network/public/interfaces",
+  ]
+  sources = [
+    "network_type_converters.cc",
+    "network_type_converters.h",
+  ]
+}
diff --git a/mojo/converters/network/network_type_converters.cc b/mojo/converters/network/network_type_converters.cc
new file mode 100644
index 0000000..94109da0
--- /dev/null
+++ b/mojo/converters/network/network_type_converters.cc
@@ -0,0 +1,17 @@
+// 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 "mojo/converters/network/network_type_converters.h"
+
+namespace mojo {
+
+// static
+URLRequestPtr TypeConverter<URLRequestPtr, std::string>::Convert(
+    const std::string& input) {
+  URLRequestPtr result(URLRequest::New());
+  result->url = input;
+  return result.Pass();
+}
+
+}  // namespace mojo
diff --git a/mojo/converters/network/network_type_converters.h b/mojo/converters/network/network_type_converters.h
new file mode 100644
index 0000000..4092cd7
--- /dev/null
+++ b/mojo/converters/network/network_type_converters.h
@@ -0,0 +1,21 @@
+// 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 MOJO_CONVERTERS_NETWORK_NETWORK_TYPE_CONVERTERS_H_
+#define MOJO_CONVERTERS_NETWORK_NETWORK_TYPE_CONVERTERS_H_
+
+#include <string>
+
+#include "mojo/services/network/public/interfaces/url_loader.mojom.h"
+
+namespace mojo {
+
+template <>
+struct TypeConverter<URLRequestPtr, std::string> {
+  static URLRequestPtr Convert(const std::string& input);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_CONVERTERS_NETWORK_NETWORK_TYPE_CONVERTERS_H_
diff --git a/mojo/services/network/public/interfaces/url_loader.mojom b/mojo/services/network/public/interfaces/url_loader.mojom
index f960109..8a18c260 100644
--- a/mojo/services/network/public/interfaces/url_loader.mojom
+++ b/mojo/services/network/public/interfaces/url_loader.mojom
@@ -35,6 +35,9 @@
   // servers to also not satisfy the request from their cache.  This has the
   // effect of forcing a full end-to-end fetch.
   bool bypass_cache = false;
+
+  // The time when this request originated. 0 indicates that it is not recorded.
+  int64 originating_time_ticks = 0;
 };
 
 struct URLResponse {
diff --git a/native_client_sdk/src/build_tools/build_sdk.py b/native_client_sdk/src/build_tools/build_sdk.py
index e99216a..04a31606 100755
--- a/native_client_sdk/src/build_tools/build_sdk.py
+++ b/native_client_sdk/src/build_tools/build_sdk.py
@@ -395,6 +395,9 @@
     ['irt_core_newlib_x32.nexe', 'irt_core_x86_32.nexe'],
     ['irt_core_newlib_x64.nexe', 'irt_core_x86_64.nexe'],
   ]
+  arm_files = [
+    ['elf_loader_newlib_arm.nexe', 'elf_loader_arm.nexe'],
+  ]
 
   tools_files_64 = []
 
@@ -429,19 +432,18 @@
       pair[0] += '.exe'
       pair[1] += '.exe'
 
-  InstallFiles(GetNinjaOutDir('x64'), tools_dir, tools_files_64)
-  InstallFiles(GetNinjaOutDir('ia32'), tools_dir, tools_files_32)
-
   # Add ARM binaries
   if platform == 'linux' and not options.no_arm_trusted:
-    arm_files = [
+    arm_files += [
       ['irt_core_newlib_arm.nexe', 'irt_core_arm.nexe'],
-      ['elf_loader_newlib_arm.nexe', 'elf_loader_arm.nexe'],
       ['nacl_helper_bootstrap', 'nacl_helper_bootstrap_arm'],
       ['nonsfi_loader_newlib_arm_nonsfi.nexe', 'nonsfi_loader_arm'],
       ['sel_ldr', 'sel_ldr_arm']
     ]
-    InstallFiles(GetNinjaOutDir('arm'), tools_dir, arm_files)
+
+  InstallFiles(GetNinjaOutDir('x64'), tools_dir, tools_files_64)
+  InstallFiles(GetNinjaOutDir('ia32'), tools_dir, tools_files_32)
+  InstallFiles(GetNinjaOutDir('arm'), tools_dir, arm_files)
 
   for tc in toolchains:
     if tc in ('host', 'clang-newlib'):
diff --git a/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json b/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
index e70bffa..88a8f663 100644
--- a/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
+++ b/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
@@ -35,26 +35,6 @@
     },
     {
       "archives": [],
-      "description": "Chrome 39 bundle, revision xxxxx",
-      "name": "pepper_39",
-      "recommended": "no",
-      "repath": "pepper_39",
-      "revision": 0,
-      "stability": "post_stable",
-      "version": 39
-    },
-    {
-      "archives": [],
-      "description": "Chrome 40 bundle, revision xxxxx",
-      "name": "pepper_40",
-      "recommended": "no",
-      "repath": "pepper_40",
-      "revision": 0,
-      "stability": "post_stable",
-      "version": 40
-    },
-    {
-      "archives": [],
       "description": "Chrome 41 bundle, revision xxxxx",
       "name": "pepper_41",
       "recommended": "no",
@@ -115,6 +95,16 @@
     },
     {
       "archives": [],
+      "description": "Chrome 47 bundle, revision xxxxx",
+      "name": "pepper_47",
+      "recommended": "no",
+      "repath": "pepper_47",
+      "revision": 0,
+      "stability": "post_stable",
+      "version": 47
+    },
+    {
+      "archives": [],
       "description": "Chrome Canary",
       "name": "pepper_canary",
       "recommended": "no",
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list
index 4ed3cdf..a502a2f2 100644
--- a/native_client_sdk/src/build_tools/sdk_files.list
+++ b/native_client_sdk/src/build_tools/sdk_files.list
@@ -455,7 +455,7 @@
 tools/create_nmf.py
 tools/decode_dump.py
 [linux,mac]tools/dump_syms
-[linux]tools/elf_loader_arm.nexe
+tools/elf_loader_arm.nexe
 tools/fix_deps.py
 tools/fix_manifest.py
 tools/genhttpfs.py
diff --git a/native_client_sdk/src/build_tools/test_sdk.py b/native_client_sdk/src/build_tools/test_sdk.py
index 355df28..b1cee6a 100755
--- a/native_client_sdk/src/build_tools/test_sdk.py
+++ b/native_client_sdk/src/build_tools/test_sdk.py
@@ -128,9 +128,6 @@
 
       for toolchain in ('clang-newlib', 'glibc', 'pnacl'):
         for arch in archs:
-          # TODO(sbc): Remove this once we get elf_loader.nexe added to the SDK
-          if toolchain == 'glibc' and arch == 'arm':
-            continue
           for config in configs:
             RunTest(location, toolchain, config, arch)
 
diff --git a/net/base/ip_address_number_unittest.cc b/net/base/ip_address_number_unittest.cc
index 2ee7bed2..0b37bfa 100644
--- a/net/base/ip_address_number_unittest.cc
+++ b/net/base/ip_address_number_unittest.cc
@@ -122,7 +122,7 @@
   EXPECT_FALSE(IsIPv4Mapped(ipv4_number));
 
   IPAddressNumber ipv6_number;
-  EXPECT_TRUE(ParseIPLiteralToNumber("::1", &ipv4_number));
+  EXPECT_TRUE(ParseIPLiteralToNumber("::1", &ipv6_number));
   EXPECT_FALSE(IsIPv4Mapped(ipv6_number));
 
   IPAddressNumber ipv4mapped_number;
diff --git a/net/net.gypi b/net/net.gypi
index 3ec18c02..79b1e2c 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -333,6 +333,8 @@
       'quic/quic_flags.h',
       'quic/quic_flow_controller.cc',
       'quic/quic_flow_controller.h',
+      'quic/quic_frame_list.cc',
+      'quic/quic_frame_list.h',
       'quic/quic_framer.cc',
       'quic/quic_framer.h',
       'quic/quic_packet_creator.cc',
diff --git a/net/quic/crypto/crypto_server_test.cc b/net/quic/crypto/crypto_server_test.cc
index a905597..5bcbc70 100644
--- a/net/quic/crypto/crypto_server_test.cc
+++ b/net/quic/crypto/crypto_server_test.cc
@@ -408,22 +408,18 @@
   }
 }
 
-// TODO(rtenneti): Enable the DefaultCert test after implementing ProofSource.
-// See http://crbug.com/514472.
 TEST_P(CryptoServerTest, DefaultCert) {
   // Check that the server replies with a default certificate when no SNI is
-  // specified.
+  // specified. The CHLO is constructed to generate a REJ with certs, so must
+  // not contain a valid STK, and must include PDMD.
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
       "AEAD", "AESG",
       "KEXS", "C255",
-      "SCID", scid_hex_.c_str(),
-      "#004b5453", srct_hex_.c_str(),
       "PUBS", pub_hex_.c_str(),
       "NONC", nonce_hex_.c_str(),
       "PDMD", "X509",
-      "XLCT", XlctHexString().c_str(),
       "VER\0", client_version_string_.c_str(),
       "$padding", static_cast<int>(kClientHelloMinimumSize),
       nullptr);
@@ -435,9 +431,15 @@
   EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof));
   EXPECT_NE(0u, cert.size());
   EXPECT_NE(0u, proof.size());
-  const HandshakeFailureReason kRejectReasons[] = {
-      CLIENT_NONCE_INVALID_TIME_FAILURE};
-  CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+  if (client_version_ <= QUIC_VERSION_26) {
+    const HandshakeFailureReason kRejectReasons[] = {
+        CLIENT_NONCE_INVALID_TIME_FAILURE};
+    CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+  } else {
+    const HandshakeFailureReason kRejectReasons[] = {
+        SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+    CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+  }
 }
 
 TEST_P(CryptoServerTest, TooSmall) {
@@ -614,14 +616,23 @@
   // clang-format on
   ShouldSucceed(msg);
   CheckRejectTag();
-  const HandshakeFailureReason kRejectReasons[] = {
-      SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE,
-      SERVER_NONCE_DECRYPTION_FAILURE,
+
+  if (client_version_ <= QUIC_VERSION_26) {
+    const HandshakeFailureReason kRejectReasons[] = {
+        SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE,
+        SERVER_NONCE_DECRYPTION_FAILURE};
+    CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+  } else {
+    const HandshakeFailureReason kRejectReasons[] = {
+        SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE};
+    CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
   };
-  CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
 }
 
 TEST_P(CryptoServerTest, ReplayProtection) {
+  if (client_version_ > QUIC_VERSION_26) {
+    return;
+  }
   // This tests that disabling replay protection works.
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc
index 8481a0e..5371438 100644
--- a/net/quic/crypto/quic_crypto_server_config.cc
+++ b/net/quic/crypto/quic_crypto_server_config.cc
@@ -120,7 +120,6 @@
                InsertStatus nonce_error) override {
     DVLOG(1) << "Using client nonce, unique: " << nonce_is_valid_and_unique
              << " nonce_error: " << nonce_error;
-    result_->info.unique = nonce_is_valid_and_unique;
     if (!nonce_is_valid_and_unique) {
       HandshakeFailureReason client_nonce_error;
       switch (nonce_error) {
@@ -168,12 +167,7 @@
 
 ClientHelloInfo::ClientHelloInfo(const IPAddressNumber& in_client_ip,
                                  QuicWallTime in_now)
-    : client_ip(in_client_ip),
-      now(in_now),
-      valid_source_address_token(false),
-      client_nonce_well_formed(false),
-      unique(false) {
-}
+    : client_ip(in_client_ip), now(in_now), valid_source_address_token(false) {}
 
 ClientHelloInfo::~ClientHelloInfo() {
 }
@@ -617,10 +611,7 @@
     return QUIC_HANDSHAKE_FAILED;
   }
 
-  if (!info.valid_source_address_token ||
-      !info.client_nonce_well_formed ||
-      !info.unique ||
-      !requested_config.get()) {
+  if (!info.reject_reasons.empty() || !requested_config.get()) {
     BuildRejection(*primary_config, client_hello, info,
                    validate_chlo_result.cached_network_params,
                    use_stateless_rejects, server_designated_connection_id, rand,
@@ -1032,10 +1023,8 @@
     }
   }
 
-  if (client_hello.GetStringPiece(kNONC, &info->client_nonce) &&
-      info->client_nonce.size() == kNonceSize) {
-    info->client_nonce_well_formed = true;
-  } else {
+  if (!client_hello.GetStringPiece(kNONC, &info->client_nonce) ||
+      info->client_nonce.size() != kNonceSize) {
     info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
     // Invalid client nonce.
     DVLOG(1) << "Invalid client nonce.";
@@ -1046,27 +1035,36 @@
     found_error = true;
   }
 
-  if (!replay_protection_) {
-    if (!found_error) {
-      info->unique = true;
+  // Server nonce is optional, and used for key derivation if present.
+  client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce);
+
+  if (version > QUIC_VERSION_26) {
+    DVLOG(1) << "No 0-RTT replay protection in QUIC_VERSION_27 and higher.";
+    // If the server nonce is empty and we're requiring handshake confirmation
+    // for DoS reasons then we must reject the CHLO.
+    if (FLAGS_quic_require_handshake_confirmation &&
+        info->server_nonce.empty()) {
+      info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE);
     }
+    helper.ValidationComplete(QUIC_NO_ERROR, "");
+    return;
+  }
+
+  if (!replay_protection_) {
     DVLOG(1) << "No replay protection.";
     helper.ValidationComplete(QUIC_NO_ERROR, "");
     return;
   }
 
-  client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce);
   if (!info->server_nonce.empty()) {
     // If the server nonce is present, use it to establish uniqueness.
     HandshakeFailureReason server_nonce_error =
         ValidateServerNonce(info->server_nonce, info->now);
-    if (server_nonce_error == HANDSHAKE_OK) {
-      info->unique = true;
-    } else {
+    bool is_unique = server_nonce_error == HANDSHAKE_OK;
+    if (!is_unique) {
       info->reject_reasons.push_back(server_nonce_error);
-      info->unique = false;
     }
-    DVLOG(1) << "Using server nonce, unique: " << info->unique;
+    DVLOG(1) << "Using server nonce, unique: " << is_unique;
     helper.ValidationComplete(QUIC_NO_ERROR, "");
     return;
   }
diff --git a/net/quic/crypto/quic_crypto_server_config.h b/net/quic/crypto/quic_crypto_server_config.h
index 4a5c83f..cb3f776 100644
--- a/net/quic/crypto/quic_crypto_server_config.h
+++ b/net/quic/crypto/quic_crypto_server_config.h
@@ -50,8 +50,6 @@
 
   // Outputs from EvaluateClientHello.
   bool valid_source_address_token;
-  bool client_nonce_well_formed;
-  bool unique;
   base::StringPiece sni;
   base::StringPiece client_nonce;
   base::StringPiece server_nonce;
@@ -145,7 +143,9 @@
   //     into a KDF before use. In tests, use TESTING.
   // |server_nonce_entropy|: an entropy source used to generate the orbit and
   //     key for server nonces, which are always local to a given instance of a
-  //     server.
+  //     server. Not owned.
+  // |proof_source|: provides certificate chains and signatures. This class
+  //     takes ownership of |proof_source|.
   QuicCryptoServerConfig(base::StringPiece source_address_token_secret,
                          QuicRandom* server_nonce_entropy);
   ~QuicCryptoServerConfig();
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index f639eb7..74a262680 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -1626,7 +1626,9 @@
     OnWriteError(result.error_code);
     DLOG(ERROR) << ENDPOINT << "failed writing " << encrypted->length()
                 << " bytes "
-                << " from host " << self_address().ToStringWithoutPort()
+                << " from host " << (self_address().address().empty()
+                                         ? " empty address "
+                                         : self_address().ToStringWithoutPort())
                 << " to address " << peer_address().ToString();
     return false;
   }
@@ -1763,7 +1765,7 @@
   if (retransmission_alarm_->IsSet()) {
     return;
   }
-  packet_generator_.AddControlFrame(QuicFrame(new QuicPingFrame));
+  packet_generator_.AddControlFrame(QuicFrame(QuicPingFrame()));
 }
 
 void QuicConnection::SendAck() {
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 9be77b9..956138f 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -416,8 +416,7 @@
       ++num_blocked_frames_sent_;
       net_log_.AddEvent(
           NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_SENT,
-          base::Bind(&NetLogQuicBlockedFrameCallback,
-                     frame.blocked_frame));
+          base::Bind(&NetLogQuicBlockedFrameCallback, frame.blocked_frame));
       break;
     case STOP_WAITING_FRAME:
       net_log_.AddEvent(
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index f60c84e..306f496 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -239,6 +239,7 @@
         framer_(SupportedVersions(version_)),
         last_packet_size_(0),
         write_blocked_(false),
+        write_should_fail_(false),
         block_on_next_write_(false),
         is_write_blocked_data_buffered_(false),
         final_bytes_of_last_packet_(0),
@@ -274,6 +275,11 @@
     if (IsWriteBlocked()) {
       return WriteResult(WRITE_STATUS_BLOCKED, -1);
     }
+
+    if (ShouldWriteFail()) {
+      return WriteResult(WRITE_STATUS_ERROR, 0);
+    }
+
     last_packet_size_ = packet.length();
 
     if (!write_pause_time_delta_.IsZero()) {
@@ -286,10 +292,14 @@
     return is_write_blocked_data_buffered_;
   }
 
+  bool ShouldWriteFail() { return write_should_fail_; }
+
   bool IsWriteBlocked() const override { return write_blocked_; }
 
   void SetWritable() override { write_blocked_ = false; }
 
+  void SetShouldWriteFail() { write_should_fail_ = true; }
+
   QuicByteCount GetMaxPacketSize(
       const IPEndPoint& /*peer_address*/) const override {
     return max_packet_size_;
@@ -383,6 +393,7 @@
   SimpleQuicFramer framer_;
   size_t last_packet_size_;
   bool write_blocked_;
+  bool write_should_fail_;
   bool block_on_next_write_;
   bool is_write_blocked_data_buffered_;
   uint32 final_bytes_of_last_packet_;
@@ -1076,7 +1087,7 @@
   QuicFrames frames;
   QuicPaddingFrame padding;
   frames.push_back(QuicFrame(&frame1_));
-  frames.push_back(QuicFrame(&padding));
+  frames.push_back(QuicFrame(padding));
   scoped_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
   scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPayload(
@@ -1107,7 +1118,7 @@
   QuicFrames frames;
   QuicPaddingFrame padding;
   frames.push_back(QuicFrame(&frame1_));
-  frames.push_back(QuicFrame(&padding));
+  frames.push_back(QuicFrame(padding));
   scoped_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   char buffer[kMaxPacketSize];
   scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPayload(
@@ -3650,6 +3661,16 @@
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
 }
 
+TEST_P(QuicConnectionTest, FailToSendFirstPacket) {
+  // Test that the connection does not crash when it fails to send the first
+  // packet at which point self_address_ might be uninitialized.
+  EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(1);
+  QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
+  writer_->SetShouldWriteFail();
+  connection_.SendPacket(ENCRYPTION_NONE, 1, packet, kTestEntropyHash,
+                         HAS_RETRANSMITTABLE_DATA, false, false);
+}
+
 TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) {
   QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
   BlockOnNextWrite();
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index 5a999ed..88b6de2d 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -141,6 +141,9 @@
   }
 
   bool AsyncStrikeRegisterVerification() {
+    if (server_connection_->version() > QUIC_VERSION_26) {
+      return false;
+    }
     return GetParam();
   }
 
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index d3e5a40..3feb646 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -51,7 +51,7 @@
 
 // If true, require handshake confirmation for QUIC connections, functionally
 // disabling 0-rtt handshakes.
-// TODO(rtenneti): Enable this flag after fixing tests.
+// TODO(rtenneti): Enable this flag after CryptoServerTest's are fixed.
 bool FLAGS_quic_require_handshake_confirmation = false;
 
 // Disables special treatment of truncated acks, since older retransmissions are
@@ -80,3 +80,8 @@
 // If true, accounts for available (implicitly opened) streams under a separate
 // quota from open streams, which is 10 times larger.
 bool FLAGS_allow_many_available_streams = true;
+
+// If true, QuicPacketReader::ReadAndDispatchPackets will only return true if
+// recvmmsg fills all of the passed in messages. Otherwise, it will return true
+// if recvmmsg read any messages.
+bool FLAGS_quic_read_packets_full_recvmmsg = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index e613ea6..bb66a23 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -28,5 +28,6 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_packet_queue_use_interval_set;
 NET_EXPORT_PRIVATE extern bool FLAGS_shift_quic_cubic_epoch_when_app_limited;
 NET_EXPORT_PRIVATE extern bool FLAGS_allow_many_available_streams;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_read_packets_full_recvmmsg;
 
 #endif  // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_frame_list.cc b/net/quic/quic_frame_list.cc
new file mode 100644
index 0000000..a69c7c6
--- /dev/null
+++ b/net/quic/quic_frame_list.cc
@@ -0,0 +1,198 @@
+// Copyright (c) 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 "net/quic/quic_frame_list.h"
+
+#include "base/logging.h"
+
+namespace net {
+
+QuicFrameList::FrameData::FrameData(QuicStreamOffset offset, string segment)
+    : offset(offset), segment(segment) {}
+
+QuicFrameList::QuicFrameList() {}
+
+QuicFrameList::~QuicFrameList() {
+  Clear();
+}
+
+QuicErrorCode QuicFrameList::WriteAtOffset(QuicStreamOffset offset,
+                                           StringPiece data,
+                                           size_t* const bytes_written) {
+  *bytes_written = 0;
+  const size_t data_len = data.size();
+  auto insertion_point = FindInsertionPoint(offset, data_len);
+  if (IsDuplicate(offset, data_len, insertion_point)) {
+    return QUIC_NO_ERROR;
+  }
+
+  if (FrameOverlapsBufferedData(offset, data_len, insertion_point)) {
+    return QUIC_INVALID_STREAM_DATA;
+  }
+
+  DVLOG(1) << "Buffering stream data at offset " << offset;
+  // Inserting an empty string and then copying to avoid the extra copy.
+  insertion_point = frame_list_.insert(insertion_point, FrameData(offset, ""));
+  data.CopyToString(&insertion_point->segment);
+  *bytes_written = data_len;
+  return QUIC_NO_ERROR;
+}
+
+// Finds the place the frame should be inserted.  If an identical frame is
+// present, stops on the identical frame.
+list<QuicFrameList::FrameData>::iterator QuicFrameList::FindInsertionPoint(
+    QuicStreamOffset offset,
+    size_t len) {
+  if (frame_list_.empty()) {
+    return frame_list_.begin();
+  }
+  // If it's after all buffered_frames, return the end.
+  if (offset >=
+      (frame_list_.rbegin()->offset + frame_list_.rbegin()->segment.length())) {
+    return frame_list_.end();
+  }
+  auto iter = frame_list_.begin();
+  // Only advance the iterator if the data begins after the already received
+  // frame.  If the new frame overlaps with an existing frame, the iterator will
+  // still point to the frame it overlaps with.
+  while (iter != frame_list_.end() &&
+         offset >= iter->offset + iter->segment.length()) {
+    ++iter;
+  }
+  return iter;
+}
+
+// Returns true if |frame| contains data which overlaps buffered data
+// (indicating an invalid stream frame has been received).
+bool QuicFrameList::FrameOverlapsBufferedData(
+    QuicStreamOffset offset,
+    size_t data_len,
+    list<FrameData>::const_iterator insertion_point) const {
+  if (frame_list_.empty() || insertion_point == frame_list_.end()) {
+    return false;
+  }
+  // If there is a buffered frame with a higher starting offset, then check to
+  // see if the new frame overlaps the beginning of the higher frame.
+  if (offset < insertion_point->offset &&
+      offset + data_len > insertion_point->offset) {
+    DVLOG(1) << "New frame overlaps next frame: " << offset << " + " << data_len
+             << " > " << insertion_point->offset;
+    return true;
+  }
+  // If there is a buffered frame with a lower starting offset, then check to
+  // see if the buffered frame runs into the new frame.
+  if (offset >= insertion_point->offset &&
+      offset < insertion_point->offset + insertion_point->segment.length()) {
+    DVLOG(1) << "Preceeding frame overlaps new frame: "
+             << insertion_point->offset << " + "
+             << insertion_point->segment.length() << " > " << offset;
+    return true;
+  }
+
+  return false;
+}
+
+// Returns true if the sequencer has received this frame before.
+bool QuicFrameList::IsDuplicate(
+    QuicStreamOffset offset,
+    size_t data_len,
+    list<FrameData>::const_iterator insertion_point) const {
+  // A frame is duplicate if the frame offset is smaller than the bytes consumed
+  // or identical to an already received frame.
+  return offset < total_bytes_read_ || (insertion_point != frame_list_.end() &&
+                                        offset == insertion_point->offset);
+}
+
+int QuicFrameList::GetReadableRegions(struct iovec* iov, int iov_len) const {
+  list<FrameData>::const_iterator it = frame_list_.begin();
+  int index = 0;
+  QuicStreamOffset offset = total_bytes_read_;
+  while (it != frame_list_.end() && index < iov_len) {
+    if (it->offset != offset) {
+      return index;
+    }
+
+    iov[index].iov_base =
+        static_cast<void*>(const_cast<char*>(it->segment.data()));
+    iov[index].iov_len = it->segment.size();
+    offset += it->segment.size();
+
+    ++index;
+    ++it;
+  }
+  return index;
+}
+
+bool QuicFrameList::IncreaseTotalReadAndInvalidate(size_t bytes_used) {
+  size_t end_offset = total_bytes_read_ + bytes_used;
+  while (!frame_list_.empty() && end_offset != total_bytes_read_) {
+    list<FrameData>::iterator it = frame_list_.begin();
+    if (it->offset != total_bytes_read_) {
+      return false;
+    }
+
+    if (it->offset + it->segment.length() <= end_offset) {
+      total_bytes_read_ += it->segment.length();
+      // This chunk is entirely consumed.
+      frame_list_.erase(it);
+      continue;
+    }
+
+    // Partially consume this frame.
+    size_t delta = end_offset - it->offset;
+    total_bytes_read_ += delta;
+    string new_data = it->segment.substr(delta);
+    frame_list_.erase(it);
+    frame_list_.push_front(FrameData(total_bytes_read_, new_data));
+    break;
+  }
+  return true;
+}
+
+size_t QuicFrameList::ReadvAndInvalidate(const struct iovec* iov,
+                                         size_t iov_len) {
+  list<FrameData>::iterator it = frame_list_.begin();
+  size_t iov_index = 0;
+  size_t iov_offset = 0;
+  size_t frame_offset = 0;
+  QuicStreamOffset initial_bytes_consumed = total_bytes_read_;
+
+  while (iov_index < iov_len && it != frame_list_.end() &&
+         it->offset == total_bytes_read_) {
+    int bytes_to_read = std::min(iov[iov_index].iov_len - iov_offset,
+                                 it->segment.size() - frame_offset);
+
+    char* iov_ptr = static_cast<char*>(iov[iov_index].iov_base) + iov_offset;
+    memcpy(iov_ptr, it->segment.data() + frame_offset, bytes_to_read);
+    frame_offset += bytes_to_read;
+    iov_offset += bytes_to_read;
+
+    if (iov[iov_index].iov_len == iov_offset) {
+      // We've filled this buffer.
+      iov_offset = 0;
+      ++iov_index;
+    }
+    if (it->segment.size() == frame_offset) {
+      // We've copied this whole frame
+      total_bytes_read_ += it->segment.size();
+      frame_list_.erase(it);
+      it = frame_list_.begin();
+      frame_offset = 0;
+    }
+  }
+  // Done copying.  If there is a partial frame, update it.
+  if (frame_offset != 0) {
+    frame_list_.push_front(
+        FrameData(it->offset + frame_offset, it->segment.substr(frame_offset)));
+    frame_list_.erase(it);
+    total_bytes_read_ += frame_offset;
+  }
+  return total_bytes_read_ - initial_bytes_consumed;
+}
+
+bool QuicFrameList::HasBytesToRead() const {
+  return !frame_list_.empty() &&
+         frame_list_.begin()->offset == total_bytes_read_;
+}
+}  // namespace net_quic
diff --git a/net/quic/quic_frame_list.h b/net/quic/quic_frame_list.h
new file mode 100644
index 0000000..55ee804
--- /dev/null
+++ b/net/quic/quic_frame_list.h
@@ -0,0 +1,99 @@
+// Copyright (c) 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 NET_QUIC_QUIC_FRAME_LIST_H_
+#define NET_QUIC_QUIC_FRAME_LIST_H_
+
+#include "net/quic/quic_frame_list.h"
+#include "net/quic/quic_protocol.h"
+
+using base::StringPiece;
+using std::string;
+using std::list;
+
+namespace net {
+
+namespace test {
+class QuicStreamSequencerPeer;
+}
+
+class NET_EXPORT_PRIVATE QuicFrameList {
+ public:
+  // A contiguous segment received by a QUIC stream.
+  struct FrameData {
+    FrameData(QuicStreamOffset offset, string segment);
+
+    const QuicStreamOffset offset;
+    string segment;
+  };
+
+  explicit QuicFrameList();
+
+  ~QuicFrameList();
+
+  // Clear the buffer such that it is in its initial, newly constructed state.
+  void Clear() { frame_list_.clear(); }
+
+  // Returns true if there is nothing to read in this buffer.
+  bool Empty() const { return frame_list_.empty(); }
+
+  // Write the supplied data to this buffer. If the write was successful,
+  // return the number of bytes written in |bytes_written|.
+  // Return QUIC_INVALID_STREAM_DATA if |data| overlaps with existing data.
+  // No data will be written.
+  // Return QUIC_NO_ERROR, if |data| is duplicated with data written previously,
+  // and |bytes_written| = 0
+  QuicErrorCode WriteAtOffset(QuicStreamOffset offset,
+                              StringPiece data,
+                              size_t* bytes_written);
+
+  // Read from this buffer into given iovec array, upto number of iov_len iovec
+  // objects.
+  // Returns the number of bytes read into iov.
+  size_t ReadvAndInvalidate(const struct iovec* iov, size_t iov_len);
+
+  // Returns the readable region of valid data in iovec format. The readable
+  // region is the buffer region where there is valid data not yet read by
+  // client. ReadAndInvalidate() and WriteAtOffset() change the readable region.
+  // The return value of this function is the number of iovec entries
+  // filled into in iov. If the region is empty, one iovec entry with 0 length
+  // is returned, and the function returns 0. If there are more readable
+  // regions than iov_size, the function only processes the first
+  // iov_size of them.
+  int GetReadableRegions(struct iovec* iov, int iov_len) const;
+
+  // Called after GetReadableRegions() to accumulate total_bytes_read_ and free
+  // up block when all data in it have been read out.
+  // Pre-requisite: bytes_used <= ReadableBytes()
+  bool IncreaseTotalReadAndInvalidate(size_t bytes_used);
+
+  // Whether there are bytes can be read out (offset == total_bytes_read_)
+  bool HasBytesToRead() const;
+
+  size_t size() const { return frame_list_.size(); }
+
+  QuicStreamOffset total_bytes_read() const { return total_bytes_read_; }
+
+ private:
+  friend class test::QuicStreamSequencerPeer;
+
+  list<FrameData>::iterator FindInsertionPoint(QuicStreamOffset offset,
+                                               size_t len);
+
+  bool FrameOverlapsBufferedData(
+      QuicStreamOffset offset,
+      size_t data_len,
+      list<FrameData>::const_iterator insertion_point) const;
+
+  bool IsDuplicate(QuicStreamOffset offset,
+                   size_t data_len,
+                   list<FrameData>::const_iterator insertion_point) const;
+
+  list<FrameData> frame_list_;
+  QuicStreamOffset total_bytes_read_ = 0;
+};
+
+}  // namespace net_quic
+
+#endif  // NET_QUIC_QUIC_FRAME_LIST_H_
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index a04824a0..9dd3d90 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -268,7 +268,8 @@
     InFecGroup is_in_fec_group,
     QuicPacketNumberLength packet_number_length) {
   // Prevent a rare crash reported in b/19458523.
-  if (frame.stream_frame == nullptr) {
+  if ((frame.type == STREAM_FRAME || frame.type == ACK_FRAME) &&
+      frame.stream_frame == nullptr) {
     LOG(DFATAL) << "Cannot compute the length of a null frame. "
                 << "type:" << frame.type << "free_bytes:" << free_bytes
                 << " first_frame:" << first_frame
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index 45710c1..5d3a7b7d 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -2924,7 +2924,7 @@
   QuicPaddingFrame padding_frame;
 
   QuicFrames frames;
-  frames.push_back(QuicFrame(&padding_frame));
+  frames.push_back(QuicFrame(padding_frame));
 
   // clang-format off
   unsigned char packet[kMaxPacketSize] = {
@@ -2973,7 +2973,7 @@
   QuicPaddingFrame padding_frame;
 
   QuicFrames frames;
-  frames.push_back(QuicFrame(&padding_frame));
+  frames.push_back(QuicFrame(padding_frame));
 
   // clang-format off
   unsigned char packet[kMaxPacketSize] = {
@@ -3021,7 +3021,7 @@
   QuicPaddingFrame padding_frame;
 
   QuicFrames frames;
-  frames.push_back(QuicFrame(&padding_frame));
+  frames.push_back(QuicFrame(padding_frame));
 
   // clang-format off
   unsigned char packet[kMaxPacketSize] = {
@@ -3069,7 +3069,7 @@
   QuicPaddingFrame padding_frame;
 
   QuicFrames frames;
-  frames.push_back(QuicFrame(&padding_frame));
+  frames.push_back(QuicFrame(padding_frame));
 
   // clang-format off
   unsigned char packet[kMaxPacketSize] = {
@@ -3944,7 +3944,7 @@
   QuicPingFrame ping_frame;
 
   QuicFrames frames;
-  frames.push_back(QuicFrame(&ping_frame));
+  frames.push_back(QuicFrame(ping_frame));
 
   // clang-format off
   unsigned char packet[] = {
@@ -3986,7 +3986,7 @@
   QuicMtuDiscoveryFrame mtu_discovery_frame;
 
   QuicFrames frames;
-  frames.push_back(QuicFrame(&mtu_discovery_frame));
+  frames.push_back(QuicFrame(mtu_discovery_frame));
 
   // clang-format off
   unsigned char packet[] = {
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index 18a719a4..8e4f174 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -451,7 +451,11 @@
   bool possibly_truncated_by_length = packet_size_ == max_plaintext_size_ &&
                                       queued_frames_.size() == 1 &&
                                       queued_frames_.back().type == ACK_FRAME;
-  char buffer[kMaxPacketSize];
+  // The optimized encryption algorithm implementations run faster when
+  // operating on aligned memory.
+  // TODO(rtenneti): Change the default 64 alignas value (used the default
+  // value from CACHELINE_SIZE).
+  ALIGNAS(64) char buffer[kMaxPacketSize];
   scoped_ptr<QuicPacket> packet;
   // Use the packet_size_ instead of the buffer size to ensure smaller
   // packet sizes are properly used.
@@ -638,8 +642,7 @@
     return;
   }
 
-  QuicPaddingFrame padding;
-  bool success = AddFrame(QuicFrame(&padding), false, false, nullptr);
+  bool success = AddFrame(QuicFrame(QuicPaddingFrame()), false, false, nullptr);
   DCHECK(success);
 }
 
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index c0565ed..4e73ba16 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -1006,7 +1006,7 @@
   EXPECT_TRUE(creator_.HasPendingFrames());
 
   QuicPaddingFrame padding_frame;
-  EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&padding_frame)));
+  EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(padding_frame)));
   EXPECT_TRUE(creator_.HasPendingFrames());
   EXPECT_EQ(0u, creator_.BytesFree());
 
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index eed8ec7d..a1a7dd2 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -57,7 +57,8 @@
   for (QuicFrame& frame : queued_control_frames_) {
     switch (frame.type) {
       case PADDING_FRAME:
-        delete frame.padding_frame;
+      case MTU_DISCOVERY_FRAME:
+      case PING_FRAME:
         break;
       case STREAM_FRAME:
         delete frame.stream_frame;
@@ -65,9 +66,6 @@
       case ACK_FRAME:
         delete frame.ack_frame;
         break;
-      case MTU_DISCOVERY_FRAME:
-        delete frame.mtu_discovery_frame;
-        break;
       case RST_STREAM_FRAME:
         delete frame.rst_stream_frame;
         break;
@@ -86,9 +84,6 @@
       case STOP_WAITING_FRAME:
         delete frame.stop_waiting_frame;
         break;
-      case PING_FRAME:
-        delete frame.ping_frame;
-        break;
       case NUM_FRAME_TYPES:
         DCHECK(false) << "Cannot delete type: " << frame.type;
     }
@@ -250,7 +245,7 @@
   // The MTU discovery frame is allocated on the stack, since it is going to be
   // serialized within this function.
   QuicMtuDiscoveryFrame mtu_discovery_frame;
-  QuicFrame frame(&mtu_discovery_frame);
+  QuicFrame frame(mtu_discovery_frame);
 
   // Send the probe packet with the new length.
   SetMaxPacketLength(target_mtu, /*force=*/true);
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index d281358f..e04902f 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -142,6 +142,8 @@
       return MakeQuicTag('Q', '0', '2', '6');
     case QUIC_VERSION_27:
       return MakeQuicTag('Q', '0', '2', '7');
+    case QUIC_VERSION_28:
+      return MakeQuicTag('Q', '0', '2', '8');
     default:
       // This shold be an ERROR because we should never attempt to convert an
       // invalid QuicVersion to be written to the wire.
@@ -172,6 +174,7 @@
     RETURN_STRING_LITERAL(QUIC_VERSION_25);
     RETURN_STRING_LITERAL(QUIC_VERSION_26);
     RETURN_STRING_LITERAL(QUIC_VERSION_27);
+    RETURN_STRING_LITERAL(QUIC_VERSION_28);
     default:
       return "QUIC_VERSION_UNSUPPORTED";
   }
@@ -263,59 +266,37 @@
 
 QuicFrame::QuicFrame() {}
 
-QuicFrame::QuicFrame(QuicPaddingFrame* padding_frame)
-    : type(PADDING_FRAME),
-      padding_frame(padding_frame) {
-}
+QuicFrame::QuicFrame(QuicPaddingFrame padding_frame)
+    : type(PADDING_FRAME), padding_frame(padding_frame) {}
 
 QuicFrame::QuicFrame(QuicStreamFrame* stream_frame)
-    : type(STREAM_FRAME),
-      stream_frame(stream_frame) {
-}
+    : type(STREAM_FRAME), stream_frame(stream_frame) {}
 
-QuicFrame::QuicFrame(QuicAckFrame* frame)
-    : type(ACK_FRAME),
-      ack_frame(frame) {
-}
+QuicFrame::QuicFrame(QuicAckFrame* frame) : type(ACK_FRAME), ack_frame(frame) {}
 
-QuicFrame::QuicFrame(QuicMtuDiscoveryFrame* frame)
-    : type(MTU_DISCOVERY_FRAME), mtu_discovery_frame(frame) {
-}
+QuicFrame::QuicFrame(QuicMtuDiscoveryFrame frame)
+    : type(MTU_DISCOVERY_FRAME), mtu_discovery_frame(frame) {}
 
 QuicFrame::QuicFrame(QuicStopWaitingFrame* frame)
-    : type(STOP_WAITING_FRAME),
-      stop_waiting_frame(frame) {
-}
+    : type(STOP_WAITING_FRAME), stop_waiting_frame(frame) {}
 
-QuicFrame::QuicFrame(QuicPingFrame* frame)
-    : type(PING_FRAME),
-      ping_frame(frame) {
-}
+QuicFrame::QuicFrame(QuicPingFrame frame)
+    : type(PING_FRAME), ping_frame(frame) {}
 
 QuicFrame::QuicFrame(QuicRstStreamFrame* frame)
-    : type(RST_STREAM_FRAME),
-      rst_stream_frame(frame) {
-}
+    : type(RST_STREAM_FRAME), rst_stream_frame(frame) {}
 
 QuicFrame::QuicFrame(QuicConnectionCloseFrame* frame)
-    : type(CONNECTION_CLOSE_FRAME),
-      connection_close_frame(frame) {
-}
+    : type(CONNECTION_CLOSE_FRAME), connection_close_frame(frame) {}
 
 QuicFrame::QuicFrame(QuicGoAwayFrame* frame)
-    : type(GOAWAY_FRAME),
-      goaway_frame(frame) {
-}
+    : type(GOAWAY_FRAME), goaway_frame(frame) {}
 
 QuicFrame::QuicFrame(QuicWindowUpdateFrame* frame)
-    : type(WINDOW_UPDATE_FRAME),
-      window_update_frame(frame) {
-}
+    : type(WINDOW_UPDATE_FRAME), window_update_frame(frame) {}
 
 QuicFrame::QuicFrame(QuicBlockedFrame* frame)
-    : type(BLOCKED_FRAME),
-      blocked_frame(frame) {
-}
+    : type(BLOCKED_FRAME), blocked_frame(frame) {}
 
 QuicFecData::QuicFecData() : fec_group(0) {}
 
@@ -785,43 +766,39 @@
 }
 
 RetransmittableFrames::~RetransmittableFrames() {
-  for (QuicFrames::iterator it = frames_.begin(); it != frames_.end(); ++it) {
-    switch (it->type) {
+  for (QuicFrame& frame : frames_) {
+    switch (frame.type) {
+      // Frames smaller than a pointer are inlined, so don't need to be deleted.
       case PADDING_FRAME:
-        delete it->padding_frame;
+      case MTU_DISCOVERY_FRAME:
+      case PING_FRAME:
         break;
       case STREAM_FRAME:
-        delete it->stream_frame;
+        delete frame.stream_frame;
         break;
       case ACK_FRAME:
-        delete it->ack_frame;
-        break;
-      case MTU_DISCOVERY_FRAME:
-        delete it->mtu_discovery_frame;
+        delete frame.ack_frame;
         break;
       case STOP_WAITING_FRAME:
-        delete it->stop_waiting_frame;
-        break;
-      case PING_FRAME:
-        delete it->ping_frame;
+        delete frame.stop_waiting_frame;
         break;
       case RST_STREAM_FRAME:
-        delete it->rst_stream_frame;
+        delete frame.rst_stream_frame;
         break;
       case CONNECTION_CLOSE_FRAME:
-        delete it->connection_close_frame;
+        delete frame.connection_close_frame;
         break;
       case GOAWAY_FRAME:
-        delete it->goaway_frame;
+        delete frame.goaway_frame;
         break;
       case WINDOW_UPDATE_FRAME:
-        delete it->window_update_frame;
+        delete frame.window_update_frame;
         break;
       case BLOCKED_FRAME:
-        delete it->blocked_frame;
+        delete frame.blocked_frame;
         break;
       case NUM_FRAME_TYPES:
-        DCHECK(false) << "Cannot delete type: " << it->type;
+        DCHECK(false) << "Cannot delete type: " << frame.type;
     }
   }
   // TODO(rtenneti): Delete the for loop once chrome has c++11 library support
@@ -893,31 +870,31 @@
 TransmissionInfo::TransmissionInfo()
     : retransmittable_frames(nullptr),
       packet_number_length(PACKET_1BYTE_PACKET_NUMBER),
-      sent_time(QuicTime::Zero()),
       bytes_sent(0),
       nack_count(0),
+      sent_time(QuicTime::Zero()),
       transmission_type(NOT_RETRANSMISSION),
-      all_transmissions(nullptr),
       in_flight(false),
       is_unackable(false),
-      is_fec_packet(false) {}
+      is_fec_packet(false),
+      all_transmissions(nullptr) {}
 
 TransmissionInfo::TransmissionInfo(
     RetransmittableFrames* retransmittable_frames,
     QuicPacketNumberLength packet_number_length,
     TransmissionType transmission_type,
     QuicTime sent_time,
-    QuicByteCount bytes_sent,
+    QuicPacketLength bytes_sent,
     bool is_fec_packet)
     : retransmittable_frames(retransmittable_frames),
       packet_number_length(packet_number_length),
-      sent_time(sent_time),
       bytes_sent(bytes_sent),
       nack_count(0),
+      sent_time(sent_time),
       transmission_type(transmission_type),
-      all_transmissions(nullptr),
       in_flight(false),
       is_unackable(false),
-      is_fec_packet(is_fec_packet) {}
+      is_fec_packet(is_fec_packet),
+      all_transmissions(nullptr) {}
 
 }  // namespace net
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index c942b8d..9d4ad54 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -51,6 +51,7 @@
 // TODO(rtenneti): Didn't use SpdyPriority because SpdyPriority is uint8 and
 // QuicPriority is uint32. Use SpdyPriority when we change the QUIC_VERSION.
 typedef uint32 QuicPriority;
+typedef uint16 QuicPacketLength;
 
 // Default initial maximum size in bytes of a QUIC packet.
 const QuicByteCount kDefaultMaxPacketSize = 1350;
@@ -346,6 +347,7 @@
                          // from QuicRstStreamFrame
   QUIC_VERSION_26 = 26,  // In CHLO, send XLCT tag containing hash of leaf cert
   QUIC_VERSION_27 = 27,  // Sends a nonce in the SHLO.
+  QUIC_VERSION_28 = 28,  // Receiver can refuse to create a requested stream.
 };
 
 // This vector contains QUIC versions which we currently support.
@@ -356,7 +358,8 @@
 // IMPORTANT: if you are adding to this list, follow the instructions at
 // http://sites/quic/adding-and-removing-versions
 static const QuicVersion kSupportedQuicVersions[] = {
-    QUIC_VERSION_27, QUIC_VERSION_26, QUIC_VERSION_25, QUIC_VERSION_24};
+    QUIC_VERSION_28, QUIC_VERSION_27, QUIC_VERSION_26, QUIC_VERSION_25,
+    QUIC_VERSION_24};
 
 typedef std::vector<QuicVersion> QuicVersionVector;
 
@@ -436,6 +439,10 @@
   // Closing stream locally, sending a RST to allow for proper flow control
   // accounting. Sent in response to a RST from the peer.
   QUIC_RST_ACKNOWLEDGEMENT,
+  // Receiver refused to create the stream (because its limit on open streams
+  // has been reached).  The sender should retry the request later (using
+  // another stream).
+  QUIC_REFUSED_STREAM,
 
   // No error. Used as bound while iterating.
   QUIC_STREAM_LAST_ERROR,
@@ -685,13 +692,11 @@
 typedef QuicPacketPublicHeader QuicVersionNegotiationPacket;
 
 // A padding frame contains no payload.
-struct NET_EXPORT_PRIVATE QuicPaddingFrame {
-};
+struct NET_EXPORT_PRIVATE QuicPaddingFrame {};
 
 // A ping frame contains no payload, though it is retransmittable,
 // and ACK'd just like other normal frames.
-struct NET_EXPORT_PRIVATE QuicPingFrame {
-};
+struct NET_EXPORT_PRIVATE QuicPingFrame {};
 
 // A path MTU discovery frame contains no payload and is serialized as a ping
 // frame.
@@ -994,15 +999,15 @@
 
 struct NET_EXPORT_PRIVATE QuicFrame {
   QuicFrame();
-  explicit QuicFrame(QuicPaddingFrame* padding_frame);
+  explicit QuicFrame(QuicPaddingFrame padding_frame);
+  explicit QuicFrame(QuicMtuDiscoveryFrame frame);
+  explicit QuicFrame(QuicPingFrame frame);
+
   explicit QuicFrame(QuicStreamFrame* stream_frame);
   explicit QuicFrame(QuicAckFrame* frame);
-  explicit QuicFrame(QuicMtuDiscoveryFrame* frame);
-
   explicit QuicFrame(QuicRstStreamFrame* frame);
   explicit QuicFrame(QuicConnectionCloseFrame* frame);
   explicit QuicFrame(QuicStopWaitingFrame* frame);
-  explicit QuicFrame(QuicPingFrame* frame);
   explicit QuicFrame(QuicGoAwayFrame* frame);
   explicit QuicFrame(QuicWindowUpdateFrame* frame);
   explicit QuicFrame(QuicBlockedFrame* frame);
@@ -1012,14 +1017,15 @@
 
   QuicFrameType type;
   union {
-    QuicPaddingFrame* padding_frame;
+    // Frames smaller than a pointer are inline.
+    QuicPaddingFrame padding_frame;
+    QuicMtuDiscoveryFrame mtu_discovery_frame;
+    QuicPingFrame ping_frame;
+
+    // Frames larger than a pointer.
     QuicStreamFrame* stream_frame;
     QuicAckFrame* ack_frame;
-    QuicMtuDiscoveryFrame* mtu_discovery_frame;
-
     QuicStopWaitingFrame* stop_waiting_frame;
-
-    QuicPingFrame* ping_frame;
     QuicRstStreamFrame* rst_stream_frame;
     QuicConnectionCloseFrame* connection_close_frame;
     QuicGoAwayFrame* goaway_frame;
@@ -1027,6 +1033,9 @@
     QuicBlockedFrame* blocked_frame;
   };
 };
+// QuicFrameType consumes 8 bytes with padding.
+static_assert(sizeof(QuicFrame) <= 16,
+              "Frames larger than 8 bytes should be referenced by pointer.");
 
 typedef std::vector<QuicFrame> QuicFrames;
 
@@ -1180,25 +1189,25 @@
                    QuicPacketNumberLength packet_number_length,
                    TransmissionType transmission_type,
                    QuicTime sent_time,
-                   QuicByteCount bytes_sent,
+                   QuicPacketLength bytes_sent,
                    bool is_fec_packet);
 
   RetransmittableFrames* retransmittable_frames;
   QuicPacketNumberLength packet_number_length;
+  QuicPacketLength bytes_sent;
+  uint16 nack_count;
   QuicTime sent_time;
-  QuicByteCount bytes_sent;
-  QuicPacketCount nack_count;
   // Reason why this packet was transmitted.
   TransmissionType transmission_type;
-  // Stores the packet numbers of all transmissions of this packet.
-  // Must always be nullptr or have multiple elements.
-  PacketNumberList* all_transmissions;
   // In flight packets have not been abandoned or lost.
   bool in_flight;
   // True if the packet can never be acked, so it can be removed.
   bool is_unackable;
   // True if the packet is an FEC packet.
   bool is_fec_packet;
+  // Stores the packet numbers of all transmissions of this packet.
+  // Must always be nullptr or have multiple elements.
+  PacketNumberList* all_transmissions;
 };
 
 // Convenience wrapper to wrap an iovec array and the total length, which must
diff --git a/net/quic/quic_protocol_test.cc b/net/quic/quic_protocol_test.cc
index c74d3d1..fcadbe9 100644
--- a/net/quic/quic_protocol_test.cc
+++ b/net/quic/quic_protocol_test.cc
@@ -14,7 +14,7 @@
 namespace {
 
 TEST(QuicProtocolTest, AdjustErrorForVersion) {
-  ASSERT_EQ(8, QUIC_STREAM_LAST_ERROR)
+  ASSERT_EQ(9, QUIC_STREAM_LAST_ERROR)
       << "Any additions to QuicRstStreamErrorCode require an addition to "
       << "AdjustErrorForVersion and this associated test.";
 
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 7875bb86..12d19039 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -679,7 +679,12 @@
     // Check if the new number of open streams would cause the number of
     // open streams to exceed the limit.
     if (GetNumOpenStreams() >= get_max_open_streams()) {
-      CloseConnection(QUIC_TOO_MANY_OPEN_STREAMS);
+      if (connection()->version() <= QUIC_VERSION_27) {
+        CloseConnection(QUIC_TOO_MANY_OPEN_STREAMS);
+      } else {
+        // Refuse to open the stream.
+        SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
+      }
       return nullptr;
     }
   }
diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc
index bd1bc6e..3989c4f9 100644
--- a/net/quic/quic_stream_sequencer.cc
+++ b/net/quic/quic_stream_sequencer.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "net/quic/quic_frame_list.h"
 #include "net/quic/reliable_quic_stream.h"
 
 using std::min;
@@ -17,10 +18,6 @@
 
 namespace net {
 
-QuicStreamSequencer::FrameData::FrameData(QuicStreamOffset offset,
-                                          const string& segment)
-    : offset(offset), segment(segment) {}
-
 QuicStreamSequencer::QuicStreamSequencer(ReliableQuicStream* quic_stream)
     : stream_(quic_stream),
       num_bytes_consumed_(0),
@@ -29,27 +26,12 @@
       num_bytes_buffered_(0),
       num_frames_received_(0),
       num_duplicate_frames_received_(0),
-      num_early_frames_received_(0) {
-}
+      num_early_frames_received_(0) {}
 
-QuicStreamSequencer::~QuicStreamSequencer() {
-}
+QuicStreamSequencer::~QuicStreamSequencer() {}
 
 void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
   ++num_frames_received_;
-  FrameList::iterator insertion_point = FindInsertionPoint(frame);
-  if (IsDuplicate(frame, insertion_point)) {
-    ++num_duplicate_frames_received_;
-    // Silently ignore duplicates.
-    return;
-  }
-
-  if (FrameOverlapsBufferedData(frame, insertion_point)) {
-    stream_->CloseConnectionWithDetails(
-        QUIC_INVALID_STREAM_FRAME, "Stream frame overlaps with buffered data.");
-    return;
-  }
-
   const QuicStreamOffset byte_offset = frame.offset;
   const size_t data_len = frame.data.length();
   if (data_len == 0 && !frame.fin) {
@@ -65,16 +47,25 @@
       return;
     }
   }
+  size_t bytes_written;
+  QuicErrorCode result =
+      buffered_frames_.WriteAtOffset(byte_offset, frame.data, &bytes_written);
+
+  if (result == QUIC_INVALID_STREAM_DATA) {
+    stream_->CloseConnectionWithDetails(
+        QUIC_INVALID_STREAM_FRAME, "Stream frame overlaps with buffered data.");
+    return;
+  }
+  if (result == QUIC_NO_ERROR && bytes_written == 0) {
+    ++num_duplicate_frames_received_;
+    // Silently ignore duplicates.
+    return;
+  }
 
   if (byte_offset > num_bytes_consumed_) {
     ++num_early_frames_received_;
   }
 
-  DVLOG(1) << "Buffering stream data at offset " << byte_offset;
-  // Inserting an empty string and then copying to avoid the extra copy.
-  insertion_point =
-      buffered_frames_.insert(insertion_point, FrameData(byte_offset, ""));
-  frame.data.CopyToString(&insertion_point->segment);
   num_bytes_buffered_ += data_len;
 
   if (blocked_) {
@@ -103,13 +94,12 @@
 bool QuicStreamSequencer::MaybeCloseStream() {
   if (!blocked_ && IsClosed()) {
     DVLOG(1) << "Passing up termination, as we've processed "
-             << num_bytes_consumed_ << " of " << close_offset_
-             << " bytes.";
+             << num_bytes_consumed_ << " of " << close_offset_ << " bytes.";
     // This will cause the stream to consume the fin.
     // Technically it's an error if num_bytes_consumed isn't exactly
     // equal, but error handling seems silly at this point.
     stream_->OnDataAvailable();
-    buffered_frames_.clear();
+    buffered_frames_.Clear();
     num_bytes_buffered_ = 0;
     return true;
   }
@@ -118,163 +108,36 @@
 
 int QuicStreamSequencer::GetReadableRegions(iovec* iov, size_t iov_len) const {
   DCHECK(!blocked_);
-  FrameList::const_iterator it = buffered_frames_.begin();
-  size_t index = 0;
-  QuicStreamOffset offset = num_bytes_consumed_;
-  while (it != buffered_frames_.end() && index < iov_len) {
-    if (it->offset != offset) {
-      return index;
-    }
-
-    iov[index].iov_base =
-        static_cast<void*>(const_cast<char*>(it->segment.data()));
-    iov[index].iov_len = it->segment.size();
-    offset += it->segment.size();
-
-    ++index;
-    ++it;
-  }
-  return index;
+  return buffered_frames_.GetReadableRegions(iov, iov_len);
 }
 
 int QuicStreamSequencer::Readv(const struct iovec* iov, size_t iov_len) {
   DCHECK(!blocked_);
-  FrameList::iterator it = buffered_frames_.begin();
-  size_t iov_index = 0;
-  size_t iov_offset = 0;
-  size_t frame_offset = 0;
-  QuicStreamOffset initial_bytes_consumed = num_bytes_consumed_;
-
-  while (iov_index < iov_len && it != buffered_frames_.end() &&
-         it->offset == num_bytes_consumed_) {
-    int bytes_to_read = min(iov[iov_index].iov_len - iov_offset,
-                            it->segment.size() - frame_offset);
-
-    char* iov_ptr = static_cast<char*>(iov[iov_index].iov_base) + iov_offset;
-    memcpy(iov_ptr, it->segment.data() + frame_offset, bytes_to_read);
-    frame_offset += bytes_to_read;
-    iov_offset += bytes_to_read;
-
-    if (iov[iov_index].iov_len == iov_offset) {
-      // We've filled this buffer.
-      iov_offset = 0;
-      ++iov_index;
-    }
-    if (it->segment.size() == frame_offset) {
-      // We've copied this whole frame
-      RecordBytesConsumed(it->segment.size());
-      buffered_frames_.erase(it);
-      it = buffered_frames_.begin();
-      frame_offset = 0;
-    }
-  }
-  // Done copying.  If there is a partial frame, update it.
-  if (frame_offset != 0) {
-    buffered_frames_.push_front(
-        FrameData(it->offset + frame_offset, it->segment.substr(frame_offset)));
-    buffered_frames_.erase(it);
-    RecordBytesConsumed(frame_offset);
-  }
-  return static_cast<int>(num_bytes_consumed_ - initial_bytes_consumed);
+  size_t bytes_read = buffered_frames_.ReadvAndInvalidate(iov, iov_len);
+  RecordBytesConsumed(bytes_read);
+  return static_cast<int>(bytes_read);
 }
 
 bool QuicStreamSequencer::HasBytesToRead() const {
-  return !buffered_frames_.empty() &&
-         buffered_frames_.begin()->offset == num_bytes_consumed_;
+  return buffered_frames_.HasBytesToRead();
 }
 
 bool QuicStreamSequencer::IsClosed() const {
   return num_bytes_consumed_ >= close_offset_;
 }
 
-QuicStreamSequencer::FrameList::iterator
-QuicStreamSequencer::FindInsertionPoint(const QuicStreamFrame& frame) {
-  if (buffered_frames_.empty()) {
-    return buffered_frames_.begin();
-  }
-  // If it's after all buffered_frames, return the end.
-  if (frame.offset >= (buffered_frames_.rbegin()->offset +
-                       buffered_frames_.rbegin()->segment.length())) {
-    return buffered_frames_.end();
-  }
-  FrameList::iterator iter = buffered_frames_.begin();
-  // Only advance the iterator if the data begins after the already received
-  // frame.  If the new frame overlaps with an existing frame, the iterator will
-  // still point to the frame it overlaps with.
-  while (iter != buffered_frames_.end() &&
-         frame.offset >= iter->offset + iter->segment.length()) {
-    ++iter;
-  }
-  return iter;
-}
-
-bool QuicStreamSequencer::FrameOverlapsBufferedData(
-    const QuicStreamFrame& frame,
-    FrameList::const_iterator insertion_point) const {
-  if (buffered_frames_.empty() || insertion_point == buffered_frames_.end()) {
-    return false;
-  }
-  // If there is a buffered frame with a higher starting offset, then check to
-  // see if the new frame overlaps the beginning of the higher frame.
-  if (frame.offset < insertion_point->offset &&
-      frame.offset + frame.data.length() > insertion_point->offset) {
-    DVLOG(1) << "New frame overlaps next frame: " << frame.offset << " + "
-             << frame.data.size() << " > " << insertion_point->offset;
-    return true;
-  }
-  // If there is a buffered frame with a lower starting offset, then check to
-  // see if the buffered frame runs into the new frame.
-  if (frame.offset >= insertion_point->offset &&
-      frame.offset <
-          insertion_point->offset + insertion_point->segment.length()) {
-    DVLOG(1) << "Preceeding frame overlaps new frame: "
-             << insertion_point->offset << " + "
-             << insertion_point->segment.length() << " > " << frame.offset;
-    return true;
-  }
-
-  return false;
-}
-
 void QuicStreamSequencer::MarkConsumed(size_t num_bytes_consumed) {
   DCHECK(!blocked_);
-  size_t end_offset = num_bytes_consumed_ + num_bytes_consumed;
-  while (!buffered_frames_.empty() && end_offset != num_bytes_consumed_) {
-    FrameList::iterator it = buffered_frames_.begin();
-    if (it->offset != num_bytes_consumed_) {
-      LOG(DFATAL) << "Invalid argument to MarkConsumed. "
-                  << " num_bytes_consumed_: " << num_bytes_consumed_
-                  << " end_offset: " << end_offset << " offset: " << it->offset
-                  << " length: " << it->segment.length();
-      stream_->Reset(QUIC_ERROR_PROCESSING_STREAM);
-      return;
-    }
-
-    if (it->offset + it->segment.length() <= end_offset) {
-      RecordBytesConsumed(it->segment.length());
-      // This chunk is entirely consumed.
-      buffered_frames_.erase(it);
-      continue;
-    }
-
-    // Partially consume this frame.
-    size_t delta = end_offset - it->offset;
-    RecordBytesConsumed(delta);
-    string new_data = it->segment.substr(delta);
-    buffered_frames_.erase(it);
-    buffered_frames_.push_front(FrameData(num_bytes_consumed_, new_data));
-    break;
+  bool result =
+      buffered_frames_.IncreaseTotalReadAndInvalidate(num_bytes_consumed);
+  if (!result) {
+    LOG(DFATAL) << "Invalid argument to MarkConsumed."
+                << " expect to consume: " << num_bytes_consumed
+                << ", but not enough bytes available.";
+    stream_->Reset(QUIC_ERROR_PROCESSING_STREAM);
+    return;
   }
-}
-
-bool QuicStreamSequencer::IsDuplicate(
-    const QuicStreamFrame& frame,
-    FrameList::const_iterator insertion_point) const {
-  // A frame is duplicate if the frame offset is smaller than the bytes consumed
-  // or identical to an already received frame.
-  return frame.offset < num_bytes_consumed_ ||
-         (insertion_point != buffered_frames_.end() &&
-          frame.offset == insertion_point->offset);
+  RecordBytesConsumed(num_bytes_consumed);
 }
 
 void QuicStreamSequencer::SetBlockedUntilFlush() {
diff --git a/net/quic/quic_stream_sequencer.h b/net/quic/quic_stream_sequencer.h
index 60a950b3..a1bdd32 100644
--- a/net/quic/quic_stream_sequencer.h
+++ b/net/quic/quic_stream_sequencer.h
@@ -9,7 +9,7 @@
 #include <string>
 
 #include "base/basictypes.h"
-#include "net/base/iovec.h"
+#include "net/quic/quic_frame_list.h"
 #include "net/quic/quic_protocol.h"
 
 namespace net {
@@ -25,19 +25,6 @@
 // up to the next layer.
 class NET_EXPORT_PRIVATE QuicStreamSequencer {
  public:
-  // A contiguous segment received by a QUIC stream.
-  struct FrameData {
-    FrameData(QuicStreamOffset offset, const std::string& segment);
-
-    const QuicStreamOffset offset;
-    std::string segment;
-  };
-
-  // TODO(alyssar) use something better than strings.
-  // Maybe write new frames into a ring buffer, and keep track of consumed
-  // bytes, and gaps.
-  typedef std::list<FrameData> FrameList;
-
   explicit QuicStreamSequencer(ReliableQuicStream* quic_stream);
   virtual ~QuicStreamSequencer();
 
@@ -93,20 +80,6 @@
  private:
   friend class test::QuicStreamSequencerPeer;
 
-  // Finds the place the frame should be inserted.  If an identical frame is
-  // present, stops on the identical frame.
-  FrameList::iterator FindInsertionPoint(const QuicStreamFrame& frame);
-
-  // Returns true if |frame| contains data which overlaps buffered data
-  // (indicating an invalid stream frame has been received).
-  bool FrameOverlapsBufferedData(
-      const QuicStreamFrame& frame,
-      FrameList::const_iterator insertion_point) const;
-
-  // Returns true if the sequencer has received this frame before.
-  bool IsDuplicate(const QuicStreamFrame& frame,
-                   FrameList::const_iterator insertion_point) const;
-
   // Wait until we've seen 'offset' bytes, and then terminate the stream.
   void CloseStreamAtOffset(QuicStreamOffset offset);
 
@@ -125,7 +98,7 @@
   QuicStreamOffset num_bytes_consumed_;
 
   // Stores buffered frames in offset order.
-  FrameList buffered_frames_;
+  QuicFrameList buffered_frames_;
 
   // The offset, if any, we got a stream termination for.  When this many bytes
   // have been processed, the sequencer will be closed.
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc
index 994ce84..a91929b 100644
--- a/net/quic/quic_stream_sequencer_test.cc
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -523,8 +523,8 @@
   // stream to be closed.
   EXPECT_CALL(stream_, Reset(QUIC_ERROR_PROCESSING_STREAM));
   EXPECT_DFATAL(sequencer_->MarkConsumed(4),
-                "Invalid argument to MarkConsumed.  num_bytes_consumed_: 3 "
-                "end_offset: 4 offset: 9 length: 17");
+                "Invalid argument to MarkConsumed."
+                " expect to consume: 4, but not enough bytes available.");
 }
 
 TEST_F(QuicStreamSequencerTest, MarkConsumedWithMissingPacket) {
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc
index 71088ae..bbe7b3f 100644
--- a/net/quic/quic_unacked_packet_map.cc
+++ b/net/quic/quic_unacked_packet_map.cc
@@ -185,7 +185,7 @@
 }
 
 void QuicUnackedPacketMap::NackPacket(QuicPacketNumber packet_number,
-                                      QuicPacketCount min_nacks) {
+                                      uint16 min_nacks) {
   DCHECK_GE(packet_number, least_unacked_);
   DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size());
   unacked_packets_[packet_number - least_unacked_].nack_count = max(
diff --git a/net/quic/quic_unacked_packet_map.h b/net/quic/quic_unacked_packet_map.h
index 1926d31..358491d 100644
--- a/net/quic/quic_unacked_packet_map.h
+++ b/net/quic/quic_unacked_packet_map.h
@@ -42,7 +42,7 @@
   bool IsUnacked(QuicPacketNumber packet_number) const;
 
   // Sets the nack count to the max of the current nack count and |min_nacks|.
-  void NackPacket(QuicPacketNumber packet_number, QuicPacketCount min_nacks);
+  void NackPacket(QuicPacketNumber packet_number, uint16 min_nacks);
 
   // Marks |packet_number| as no longer in flight.
   void RemoveFromInFlight(QuicPacketNumber packet_number);
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index 641818e..b336202 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -146,6 +146,7 @@
     RETURN_STRING_LITERAL(QUIC_STREAM_PEER_GOING_AWAY);
     RETURN_STRING_LITERAL(QUIC_STREAM_CANCELLED);
     RETURN_STRING_LITERAL(QUIC_RST_ACKNOWLEDGEMENT);
+    RETURN_STRING_LITERAL(QUIC_REFUSED_STREAM);
     RETURN_STRING_LITERAL(QUIC_STREAM_LAST_ERROR);
   }
   // Return a default value so that we return this when |error| doesn't match
diff --git a/net/quic/test_tools/crypto_test_utils_chromium.cc b/net/quic/test_tools/crypto_test_utils_chromium.cc
index 366dd5e2..ffa1788 100644
--- a/net/quic/test_tools/crypto_test_utils_chromium.cc
+++ b/net/quic/test_tools/crypto_test_utils_chromium.cc
@@ -116,7 +116,7 @@
   ProofSourceChromium* source = new ProofSourceChromium();
   base::FilePath certs_dir = GetTestCertsDirectory();
   CHECK(source->Initialize(
-      certs_dir.AppendASCII("quic_chain.crt"),
+      certs_dir.AppendASCII("quic_test.example.com.crt"),
       certs_dir.AppendASCII("quic_test.example.com.key.pkcs8")));
   return source;
 }
diff --git a/net/quic/test_tools/quic_stream_sequencer_peer.cc b/net/quic/test_tools/quic_stream_sequencer_peer.cc
index 591a2e9e..0d2c61b 100644
--- a/net/quic/test_tools/quic_stream_sequencer_peer.cc
+++ b/net/quic/test_tools/quic_stream_sequencer_peer.cc
@@ -22,9 +22,11 @@
 bool QuicStreamSequencerPeer::FrameOverlapsBufferedData(
     QuicStreamSequencer* sequencer,
     const QuicStreamFrame& frame) {
-  QuicStreamSequencer::FrameList::iterator it =
-      sequencer->FindInsertionPoint(frame);
-  return sequencer->FrameOverlapsBufferedData(frame, it);
+  list<QuicFrameList::FrameData>::iterator it =
+      sequencer->buffered_frames_.FindInsertionPoint(frame.offset,
+                                                     frame.data.length());
+  return sequencer->buffered_frames_.FrameOverlapsBufferedData(
+      frame.offset, frame.data.length(), it);
 }
 
 // static
diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc
index 3472fd0..cf8f40a 100644
--- a/net/socket/ssl_client_socket.cc
+++ b/net/socket/ssl_client_socket.cc
@@ -127,14 +127,13 @@
 void SSLClientSocket::RecordChannelIDSupport(
     ChannelIDService* channel_id_service,
     bool negotiated_channel_id,
-    bool channel_id_enabled,
-    bool supports_ecc) {
+    bool channel_id_enabled) {
   // Since this enum is used for a histogram, do not change or re-use values.
   enum {
     DISABLED = 0,
     CLIENT_ONLY = 1,
     CLIENT_AND_SERVER = 2,
-    CLIENT_NO_ECC = 3,
+    // CLIENT_NO_ECC is unused now.
     // CLIENT_BAD_SYSTEM_TIME is unused now.
     CLIENT_BAD_SYSTEM_TIME = 4,
     CLIENT_NO_CHANNEL_ID_SERVICE = 5,
@@ -145,8 +144,6 @@
   } else if (channel_id_enabled) {
     if (!channel_id_service)
       supported = CLIENT_NO_CHANNEL_ID_SERVICE;
-    else if (!supports_ecc)
-      supported = CLIENT_NO_ECC;
     else
       supported = CLIENT_ONLY;
   }
@@ -164,10 +161,6 @@
     DVLOG(1) << "NULL channel_id_service_, not enabling channel ID.";
     return false;
   }
-  if (!crypto::ECPrivateKey::IsSupported()) {
-    DVLOG(1) << "Elliptic Curve not supported, not enabling channel ID.";
-    return false;
-  }
   return true;
 }
 
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index 1d38048d0..e3df669 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -152,11 +152,9 @@
 
   // Records histograms for channel id support during full handshakes - resumed
   // handshakes are ignored.
-  static void RecordChannelIDSupport(
-      ChannelIDService* channel_id_service,
-      bool negotiated_channel_id,
-      bool channel_id_enabled,
-      bool supports_ecc);
+  static void RecordChannelIDSupport(ChannelIDService* channel_id_service,
+                                     bool negotiated_channel_id,
+                                     bool channel_id_enabled);
 
   // Returns whether TLS channel ID is enabled.
   static bool IsChannelIDEnabled(
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 9f3aff6..29d8394 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -648,10 +648,8 @@
   void OnNSSBufferUpdated(int amount_in_read_buffer);
   void DidNSSRead(int result);
   void DidNSSWrite(int result);
-  void RecordChannelIDSupportOnNetworkTaskRunner(
-      bool negotiated_channel_id,
-      bool channel_id_enabled,
-      bool supports_ecc) const;
+  void RecordChannelIDSupportOnNetworkTaskRunner(bool negotiated_channel_id,
+                                                 bool channel_id_enabled) const;
 
   ////////////////////////////////////////////////////////////////////////////
   // Methods that are called on both the network task runner and the NSS
@@ -2131,23 +2129,17 @@
   // network task runner state.
   PostOrRunCallback(
       FROM_HERE,
-      base::Bind(&Core::RecordChannelIDSupportOnNetworkTaskRunner,
-                 this,
-                 channel_id_xtn_negotiated_,
-                 ssl_config_.channel_id_enabled,
-                 crypto::ECPrivateKey::IsSupported()));
+      base::Bind(&Core::RecordChannelIDSupportOnNetworkTaskRunner, this,
+                 channel_id_xtn_negotiated_, ssl_config_.channel_id_enabled));
 }
 
 void SSLClientSocketNSS::Core::RecordChannelIDSupportOnNetworkTaskRunner(
     bool negotiated_channel_id,
-    bool channel_id_enabled,
-    bool supports_ecc) const {
+    bool channel_id_enabled) const {
   DCHECK(OnNetworkTaskRunner());
 
-  RecordChannelIDSupport(channel_id_service_,
-                         negotiated_channel_id,
-                         channel_id_enabled,
-                         supports_ecc);
+  RecordChannelIDSupport(channel_id_service_, negotiated_channel_id,
+                         channel_id_enabled);
 }
 
 int SSLClientSocketNSS::Core::DoBufferRecv(IOBuffer* read_buffer, int len) {
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index 92bf8f0..d575259 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -1116,8 +1116,7 @@
 
   RecordNegotiationExtension();
   RecordChannelIDSupport(channel_id_service_, channel_id_sent_,
-                         ssl_config_.channel_id_enabled,
-                         crypto::ECPrivateKey::IsSupported());
+                         ssl_config_.channel_id_enabled);
 
   // Only record OCSP histograms if OCSP was requested.
   if (ssl_config_.signed_cert_timestamps_enabled ||
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 9f4ccaaa..dd13bcb6 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -1100,9 +1100,15 @@
   }
   client_->WaitForResponse();
 
-  EXPECT_FALSE(client_->connected());
-  EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
-  EXPECT_EQ(QUIC_TOO_MANY_OPEN_STREAMS, client_->connection_error());
+  if (negotiated_version_ <= QUIC_VERSION_27) {
+    EXPECT_FALSE(client_->connected());
+    EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
+    EXPECT_EQ(QUIC_TOO_MANY_OPEN_STREAMS, client_->connection_error());
+  } else {
+    EXPECT_TRUE(client_->connected());
+    EXPECT_EQ(QUIC_REFUSED_STREAM, client_->stream_error());
+    EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error());
+  }
 }
 
 TEST_P(EndToEndTest, NegotiateCongestionControl) {
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 0a103ac6..31cc8e36 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -487,7 +487,7 @@
   time_wait_list_writer_.reset(
       packet_writer_factory_->Create(writer_.get(), nullptr));
   return new QuicTimeWaitListManager(time_wait_list_writer_.get(), this,
-                                     helper_.get(), supported_versions());
+                                     helper_.get());
 }
 
 bool QuicDispatcher::HandlePacketForTimeWait(
diff --git a/net/tools/quic/quic_packet_reader.cc b/net/tools/quic/quic_packet_reader.cc
index 1982269..1f368a6 100644
--- a/net/tools/quic/quic_packet_reader.cc
+++ b/net/tools/quic/quic_packet_reader.cc
@@ -14,6 +14,7 @@
 
 #include "base/logging.h"
 #include "net/base/ip_endpoint.h"
+#include "net/quic/quic_flags.h"
 #include "net/tools/quic/quic_dispatcher.h"
 #include "net/tools/quic/quic_socket_utils.h"
 
@@ -103,7 +104,12 @@
                                            packets_dropped);
   }
 
-  return true;
+  if (FLAGS_quic_read_packets_full_recvmmsg) {
+    // We may not have read all of the packets available on the socket.
+    return packets_read == kNumPacketsPerReadMmsgCall;
+  } else {
+    return true;
+  }
 #else
   LOG(FATAL) << "Unsupported";
   return false;
diff --git a/net/tools/quic/quic_packet_reader.h b/net/tools/quic/quic_packet_reader.h
index 479fc6d..e667d59 100644
--- a/net/tools/quic/quic_packet_reader.h
+++ b/net/tools/quic/quic_packet_reader.h
@@ -37,8 +37,8 @@
   virtual ~QuicPacketReader();
 
   // Reads a number of packets from the given fd, and then passes them off to
-  // the PacketProcessInterface.  Returns true if at least 1 packet is read,
-  // false otherwise.
+  // the PacketProcessInterface.  Returns true if there may be additional
+  // packets available on the socket.
   // Populates |packets_dropped| if it is non-null and the socket is configured
   // to track dropped packets and some packets are read.
   virtual bool ReadAndDispatchPackets(int fd,
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc
index 392963d2..e0cd873d 100644
--- a/net/tools/quic/quic_server.cc
+++ b/net/tools/quic/quic_server.cc
@@ -47,17 +47,7 @@
 
 }  // namespace
 
-QuicServer::QuicServer()
-    : port_(0),
-      fd_(-1),
-      packets_dropped_(0),
-      overflow_supported_(false),
-      use_recvmmsg_(false),
-      crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()),
-      supported_versions_(QuicSupportedVersions()),
-      packet_reader_(new QuicPacketReader()) {
-  Initialize();
-}
+QuicServer::QuicServer() : QuicServer(QuicConfig(), QuicSupportedVersions()) {}
 
 QuicServer::QuicServer(const QuicConfig& config,
                        const QuicVersionVector& supported_versions)
@@ -215,14 +205,14 @@
 
   if (event->in_events & EPOLLIN) {
     DVLOG(1) << "EPOLLIN";
-    bool read = true;
-    while (read) {
+    bool more_to_read = true;
+    while (more_to_read) {
       if (use_recvmmsg_) {
-        read = packet_reader_->ReadAndDispatchPackets(
+        more_to_read = packet_reader_->ReadAndDispatchPackets(
             fd_, port_, dispatcher_.get(),
             overflow_supported_ ? &packets_dropped_ : nullptr);
       } else {
-        read = QuicPacketReader::ReadAndDispatchSinglePacket(
+        more_to_read = QuicPacketReader::ReadAndDispatchSinglePacket(
             fd_, port_, dispatcher_.get(),
             overflow_supported_ ? &packets_dropped_ : nullptr);
       }
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc
index 7123496..d24b8378b 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -189,9 +189,9 @@
 }
 
 TEST_P(QuicServerSessionTest, MaxOpenStreams) {
-  // Test that the server closes the connection if a client attempts to open too
-  // many data streams. The server accepts slightly more than the negotiated
-  // stream limit to deal with rare cases where a client FIN/RST is lost.
+  // Test that the server refuses if a client attempts to open too many data
+  // streams.  The server accepts slightly more than the negotiated stream limit
+  // to deal with rare cases where a client FIN/RST is lost.
 
   // The slightly increased stream limit is set during config negotiation.  It
   // is either an increase of 10 over negotiated limit, or a fixed percentage
@@ -220,8 +220,14 @@
 
   // Now violate the server's internal stream limit.
   stream_id += 2;
-  EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS));
-  EXPECT_CALL(*connection_, SendRstStream(_, _, _)).Times(0);
+  if (connection_->version() <= QUIC_VERSION_27) {
+    EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS));
+    EXPECT_CALL(*connection_, SendRstStream(_, _, _)).Times(0);
+  } else {
+    EXPECT_CALL(*connection_, SendConnectionClose(_)).Times(0);
+    EXPECT_CALL(*connection_, SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0));
+  }
+  // Even if the connection remains open, the stream creation should fail.
   EXPECT_FALSE(QuicServerSessionPeer::GetIncomingDynamicStream(session_.get(),
                                                                stream_id));
 }
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc
index 68d1b9e..1e433e5 100644
--- a/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -80,8 +80,7 @@
 QuicTimeWaitListManager::QuicTimeWaitListManager(
     QuicPacketWriter* writer,
     QuicServerSessionVisitor* visitor,
-    QuicConnectionHelperInterface* helper,
-    const QuicVersionVector& supported_versions)
+    QuicConnectionHelperInterface* helper)
     : time_wait_period_(
           QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)),
       connection_id_clean_up_alarm_(
diff --git a/net/tools/quic/quic_time_wait_list_manager.h b/net/tools/quic/quic_time_wait_list_manager.h
index 9a9eccd5..092f116 100644
--- a/net/tools/quic/quic_time_wait_list_manager.h
+++ b/net/tools/quic/quic_time_wait_list_manager.h
@@ -44,8 +44,7 @@
   // helper - used to run clean up alarms. (Owned by the dispatcher)
   QuicTimeWaitListManager(QuicPacketWriter* writer,
                           QuicServerSessionVisitor* visitor,
-                          QuicConnectionHelperInterface* helper,
-                          const QuicVersionVector& supported_versions);
+                          QuicConnectionHelperInterface* helper);
   ~QuicTimeWaitListManager() override;
 
   // Adds the given connection_id to time wait state for time_wait_period_.
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc
index e6baf7d..8f5fd89 100644
--- a/net/tools/quic/quic_time_wait_list_manager_test.cc
+++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -96,10 +96,7 @@
  protected:
   QuicTimeWaitListManagerTest()
       : helper_(&epoll_server_),
-        time_wait_list_manager_(&writer_,
-                                &visitor_,
-                                &helper_,
-                                QuicSupportedVersions()),
+        time_wait_list_manager_(&writer_, &visitor_, &helper_),
         framer_(QuicSupportedVersions(),
                 QuicTime::Zero(),
                 Perspective::IS_SERVER),
diff --git a/net/tools/quic/test_tools/mock_quic_time_wait_list_manager.cc b/net/tools/quic/test_tools/mock_quic_time_wait_list_manager.cc
index 7801db5..8e972f3 100644
--- a/net/tools/quic/test_tools/mock_quic_time_wait_list_manager.cc
+++ b/net/tools/quic/test_tools/mock_quic_time_wait_list_manager.cc
@@ -16,10 +16,7 @@
     QuicPacketWriter* writer,
     QuicServerSessionVisitor* visitor,
     QuicConnectionHelperInterface* helper)
-    : QuicTimeWaitListManager(writer,
-                              visitor,
-                              helper,
-                              QuicSupportedVersions()) {
+    : QuicTimeWaitListManager(writer, visitor, helper) {
   // Though AddConnectionIdToTimeWait is mocked, we want to retain its
   // functionality.
   EXPECT_CALL(*this, AddConnectionIdToTimeWait(_, _, _, _))
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 718f0cf..708b4f8 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -109,12 +109,11 @@
     const QuicServerId& server_id,
     const QuicVersionVector& supported_versions,
     EpollServer* epoll_server)
-    : QuicClient(server_address,
-                 server_id,
-                 supported_versions,
-                 epoll_server),
-      override_connection_id_(0),
-      test_writer_(nullptr) {}
+    : MockableQuicClient(server_address,
+                         server_id,
+                         QuicConfig(),
+                         supported_versions,
+                         epoll_server) {}
 
 MockableQuicClient::MockableQuicClient(
     IPEndPoint server_address,
@@ -164,36 +163,29 @@
                                const string& server_hostname,
                                bool secure,
                                const QuicVersionVector& supported_versions)
+    : QuicTestClient(server_address,
+                     server_hostname,
+                     secure,
+                     QuicConfig(),
+                     supported_versions) {}
+
+QuicTestClient::QuicTestClient(IPEndPoint server_address,
+                               const string& server_hostname,
+                               bool secure,
+                               const QuicConfig& config,
+                               const QuicVersionVector& supported_versions)
     : client_(new MockableQuicClient(server_address,
                                      QuicServerId(server_hostname,
                                                   server_address.port(),
                                                   secure,
                                                   PRIVACY_MODE_DISABLED),
+                                     config,
                                      supported_versions,
                                      &epoll_server_)) {
   Initialize(secure);
 }
 
-QuicTestClient::QuicTestClient(
-    IPEndPoint server_address,
-    const string& server_hostname,
-    bool secure,
-    const QuicConfig& config,
-    const QuicVersionVector& supported_versions)
-    : client_(
-          new MockableQuicClient(server_address,
-                                 QuicServerId(server_hostname,
-                                              server_address.port(),
-                                              secure,
-                                              PRIVACY_MODE_DISABLED),
-                                 config,
-                                 supported_versions,
-                                 &epoll_server_)) {
-  Initialize(secure);
-}
-
-QuicTestClient::QuicTestClient() {
-}
+QuicTestClient::QuicTestClient() {}
 
 QuicTestClient::~QuicTestClient() {
   if (stream_) {
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index cfa11ba9..12aad3ca 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -156,6 +156,14 @@
 
 static const char kPPPPdfInterface[] = PPP_PDF_INTERFACE_1;
 
+// Used for UMA. Do not delete entries, and keep in sync with histograms.xml.
+enum PDFFeatures {
+  LOADED_DOCUMENT = 0,
+  HAS_TITLE = 1,
+  HAS_BOOKMARKS = 2,
+  FEATURES_COUNT
+};
+
 PP_Var GetLinkAtPosition(PP_Instance instance, PP_Point point) {
   pp::Var var;
   void* object = pp::Instance::GetPerInstanceObject(instance, kPPPPdfInterface);
@@ -1101,6 +1109,8 @@
   DCHECK(document_load_state_ == LOAD_STATE_LOADING);
   document_load_state_ = LOAD_STATE_COMPLETE;
   UserMetricsRecordAction("PDF.LoadSuccess");
+  uma_.HistogramEnumeration("PDF.DocumentFeature", LOADED_DOCUMENT,
+                            FEATURES_COUNT);
 
   // Note: If we are in print preview mode the scroll location is retained
   // across document loads so we don't want to scroll again and override it.
@@ -1112,10 +1122,17 @@
   pp::VarDictionary metadata_message;
   metadata_message.Set(pp::Var(kType), pp::Var(kJSMetadataType));
   std::string title = engine_->GetMetadata("Title");
-  if (!base::TrimWhitespace(base::UTF8ToUTF16(title), base::TRIM_ALL).empty())
+  if (!base::TrimWhitespace(base::UTF8ToUTF16(title), base::TRIM_ALL).empty()) {
     metadata_message.Set(pp::Var(kJSTitle), pp::Var(title));
+    uma_.HistogramEnumeration("PDF.DocumentFeature", HAS_TITLE, FEATURES_COUNT);
+  }
 
-  metadata_message.Set(pp::Var(kJSBookmarks), engine_->GetBookmarks());
+  pp::VarArray bookmarks = engine_->GetBookmarks();
+  metadata_message.Set(pp::Var(kJSBookmarks), bookmarks);
+  if (bookmarks.GetLength() > 0) {
+    uma_.HistogramEnumeration("PDF.DocumentFeature", HAS_BOOKMARKS,
+                              FEATURES_COUNT);
+  }
   PostMessage(metadata_message);
 
   pp::VarDictionary progress_message;
diff --git a/ppapi/shared_impl/BUILD.gn b/ppapi/shared_impl/BUILD.gn
index 25ad9043..3b92a0a 100644
--- a/ppapi/shared_impl/BUILD.gn
+++ b/ppapi/shared_impl/BUILD.gn
@@ -159,6 +159,11 @@
     "PPAPI_THUNK_IMPLEMENTATION",
   ]
 
+  public_deps = [
+    "//ppapi/c",
+    "//ppapi/thunk",
+  ]
+
   deps = [
     "//base",
     "//base:i18n",
@@ -169,8 +174,6 @@
     "//gpu/command_buffer/common",
     "//ipc",
     "//media:shared_memory_support",
-    "//ppapi/c",
-    "//ppapi/thunk",
     "//third_party/icu:icuuc",
     "//url",
   ]
diff --git a/remoting/protocol/jingle_session_unittest.cc b/remoting/protocol/jingle_session_unittest.cc
index a3e986b..8a643c36 100644
--- a/remoting/protocol/jingle_session_unittest.cc
+++ b/remoting/protocol/jingle_session_unittest.cc
@@ -530,11 +530,12 @@
   config->PreferTransport(ChannelConfig::TRANSPORT_QUIC_STREAM);
   client_server_->set_protocol_config(config.Pass());
 
+  ExpectRouteChange(kQuicChannelName);
+
   ASSERT_NO_FATAL_FAILURE(
       InitiateConnection(1, FakeAuthenticator::ACCEPT, false));
 
   int counter = 2;
-  ExpectRouteChange(kQuicChannelName);
   EXPECT_CALL(client_channel_callback_, OnDone(_))
       .WillOnce(QuitThreadOnCounter(&counter));
   EXPECT_CALL(host_channel_callback_, OnDone(_))
diff --git a/testing/chromoting/browser_tests_launcher.py b/testing/chromoting/browser_tests_launcher.py
index 9d33bce4..bb222b7 100644
--- a/testing/chromoting/browser_tests_launcher.py
+++ b/testing/chromoting/browser_tests_launcher.py
@@ -7,6 +7,7 @@
 import argparse
 import time
 
+from chromoting_test_utilities import CleanupUserProfileDir
 from chromoting_test_utilities import GetJidListFromTestResults
 from chromoting_test_utilities import InitialiseTestMachineForLinux
 from chromoting_test_utilities import PrintHostLogContents
@@ -48,7 +49,10 @@
     # It returns the file-name of the me2me host log.
     # If we are attempting to run this test because of a JID-mismatch, don't
     # restart host.
-    if not host_jid_mismatch:
+    if host_jid_mismatch:
+      # Cleanup user-profile directory, but don't restart host.
+      CleanupUserProfileDir(args)
+    else:
       host_log_file_names.append(TestCaseSetup(args))
       # Parse the me2me host log to obtain the JID that the host registered.
       host_jid = None
diff --git a/testing/chromoting/chromoting_test_utilities.py b/testing/chromoting/chromoting_test_utilities.py
index 79620f43..bcc84d07 100644
--- a/testing/chromoting/chromoting_test_utilities.py
+++ b/testing/chromoting/chromoting_test_utilities.py
@@ -152,6 +152,11 @@
   return log_file
 
 
+def CleanupUserProfileDir(args):
+  SetupUserProfileDir(args.me2me_manifest_file, args.it2me_manifest_file,
+                      args.user_profile_dir)
+
+
 def SetupUserProfileDir(me2me_manifest_file, it2me_manifest_file,
                         user_profile_dir):
   """Sets up the Google Chrome user profile directory.
@@ -203,13 +208,10 @@
 
 
 def TestCaseSetup(args):
-  # Stop+start me2me host process.
-  host_log_file = RestartMe2MeHost()
-
   # Reset the user profile directory to start each test with a clean slate.
-  SetupUserProfileDir(args.me2me_manifest_file, args.it2me_manifest_file,
-                      args.user_profile_dir)
-  return host_log_file
+  CleanupUserProfileDir(args)
+  # Stop+start me2me host process.
+  return RestartMe2MeHost()
 
 
 def GetJidListFromTestResults(results):
diff --git a/testing/test.gni b/testing/test.gni
index 73750394..150c0d8 100644
--- a/testing/test.gni
+++ b/testing/test.gni
@@ -80,15 +80,26 @@
       }
     }
 
-    test_name = main_target_name
+    _test_name = main_target_name
     if (defined(invoker.output_name)) {
-      test_name = invoker.output_name
+      _test_name = invoker.output_name
     }
-    test_runner_script_name = "${test_name}__test_runner_script"
+    test_runner_script_name = "${_test_name}__test_runner_script"
     test_runner_script(test_runner_script_name) {
-      test_name = test_name
+      test_name = _test_name
       test_type = "gtest"
-      test_suite = test_name
+      test_suite = _test_name
+      if (defined(invoker.isolate_file)) {
+        isolate_file = invoker.isolate_file
+      }
+    }
+    incremental_test_runner_script_name =
+        "${_test_name}_incremental__test_runner_script"
+    test_runner_script(incremental_test_runner_script_name) {
+      test_name = "${_test_name}_incremental"
+      test_type = "gtest"
+      test_suite = _test_name
+      incremental_install = true
       if (defined(invoker.isolate_file)) {
         isolate_file = invoker.isolate_file
       }
@@ -100,10 +111,18 @@
         ":$test_runner_script_name",
       ]
       deps = [
-        ":$library_name",
         ":$apk_name",
       ]
     }
+    group("${target_name}_incremental") {
+      testonly = true
+      datadeps = [
+        ":$incremental_test_runner_script_name",
+      ]
+      deps = [
+        ":${apk_name}_incremental",
+      ]
+    }
   } else if (is_ios) {
     if (is_ios) {
       import("//build/config/ios/rules.gni")
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index eccd88ac..55f0f7ae 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -691,8 +691,6 @@
 
 crbug.com/443379 imported/web-platform-tests/gamepad/idlharness.html [ Failure Timeout ]
 
-crbug.com/443382 imported/web-platform-tests/subresource-integrity/subresource-integrity.html [ Failure Timeout ]
-
 crbug.com/396775 compositing/overflow/reflected-overlay-scrollbars-should-appear-without-compositing.html [ ImageOnlyFailure ]
 crbug.com/396775 virtual/prefer_compositing_to_lcd_text/compositing/overflow/reflected-overlay-scrollbars-should-appear-without-compositing.html [ ImageOnlyFailure ]
 
@@ -1617,6 +1615,7 @@
 crbug.com/471824 virtual/pointerevent/imported/web-platform-tests/pointerevents/pointerevent_touch-action-verification.html [ Skip ]
 
 crbug.com/470429 inspector/tracing/worker-js-profile.html [ Skip ]
+crbug.com/470429 virtual/threaded/inspector/tracing/worker-js-profile.html [ Skip ]
 
 crbug.com/471066 [ SnowLeopard ] fast/text/apply-start-width-after-skipped-text.html [ Failure ]
 crbug.com/471066 [ SnowLeopard ] fast/text/bidi-explicit-embedding-past-end.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations
index 9ab692da..d267c7b4 100644
--- a/third_party/WebKit/LayoutTests/W3CImportExpectations
+++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -158,8 +158,8 @@
 imported/web-platform-tests/service-workers [ Skip ]
 ## Owners: kochi@chromium.org crbug.com/505364
 # imported/web-platform-tests/shadow-dom [ Pass ]
-## Owners: mkwst@chromium.org
-# imported/web-platform-tests/subresource-integrity [ Pass ]
+## Owners: jww@chromium.org
+imported/web-platform-tests/subresource-integrity [ Skip ]
 imported/web-platform-tests/svg [ Skip ]
 imported/web-platform-tests/tools [ Skip ]
 imported/web-platform-tests/touch-events [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/select-accesskey-change-event.html b/third_party/WebKit/LayoutTests/fast/forms/select/select-accesskey-change-event.html
new file mode 100644
index 0000000..00ec32d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/select/select-accesskey-change-event.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<body>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<div id=log></div>
+<select onchange="handleChange();">
+<option accesskey=1 selcted>o1
+<option accesskey=2>o2
+</select>
+
+<script>
+var changeEventCounter = 0;
+var select1 = document.querySelector('select');
+
+function handleChange() {
+    ++changeEventCounter;
+}
+
+test(function() {
+    changeEventCounter = 0;
+    assert_equals(select1.selectedIndex, 0);
+    eventSender.keyDown('1', 'accessKey');
+    assert_equals(select1.selectedIndex, -1);
+    assert_equals(changeEventCounter, 1);
+}, 'Change event should be dsiaptched after deselecting the selected OPTION by accesskey.');
+
+test(function() {
+    changeEventCounter = 0;
+    assert_equals(select1.selectedIndex, -1);
+    eventSender.keyDown('1', 'accessKey');
+    assert_equals(select1.selectedIndex, 0);
+    assert_equals(changeEventCounter, 1);
+}, 'Change event should be dsiaptched after selecting the selected OPTION by accesskey again.');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/mediarecorder/BlobEvent-basic.html b/third_party/WebKit/LayoutTests/fast/mediarecorder/BlobEvent-basic.html
index 64e9f80..b8c5059 100644
--- a/third_party/WebKit/LayoutTests/fast/mediarecorder/BlobEvent-basic.html
+++ b/third_party/WebKit/LayoutTests/fast/mediarecorder/BlobEvent-basic.html
@@ -12,14 +12,10 @@
   reader.addEventListener("loadend", function() {
     // |reader.result| contains the contents of blob as an ArrayBuffer.
     var outputArray = new Uint8Array(reader.result);
-    assert_equals(array.length, outputArray.length);
-    for (var index in outputArray) {
-      assert_equals(array[index], outputArray[index]);
-    }
+    assert_array_equals(array, outputArray)
   });
   reader.readAsArrayBuffer(blob);
 
 }, 'check BlobEvent creation and content management');
 
-
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/text/sub-pixel/text-scaling-webfont.html b/third_party/WebKit/LayoutTests/fast/text/sub-pixel/text-scaling-webfont.html
index 9a983cb..e4a1481 100644
--- a/third_party/WebKit/LayoutTests/fast/text/sub-pixel/text-scaling-webfont.html
+++ b/third_party/WebKit/LayoutTests/fast/text/sub-pixel/text-scaling-webfont.html
@@ -31,18 +31,25 @@
                 window.testRunner.setTextSubpixelPositioning(true);
 
             var PANGRAM = 'My faxed joke won a pager in the cable TV quiz show.';
-            var results = runTest(document.getElementById('test'), PANGRAM);
-            
-            if (results == PASS) {
-                testPassed('Size of text scales smoothly and width scales with font size as expected.');
-                
-                // Hide text if test passes as the actual numbers are
-                // different across platforms and would require platform
-                // specific baselines.
-                if (window.testRunner)
-                    document.getElementById('test').style.display = 'none';
-            } else {
-                testFailed('Size of text does not scale smoothly, reported widths highlighted in red do not match reference row.');
+
+            jsTestIsAsync = true;
+            document.fonts.ready.then(testAndReport);
+
+            function testAndReport() {
+                var results = runTest(document.getElementById('test'), PANGRAM);
+
+                if (results == PASS) {
+                    testPassed('Size of text scales smoothly and width scales with font size as expected.');
+
+                    // Hide text if test passes as the actual numbers are
+                    // different across platforms and would require platform
+                    // specific baselines.
+                    if (window.testRunner)
+                        document.getElementById('test').style.display = 'none';
+                } else {
+                    testFailed('Size of text does not scale smoothly, reported widths highlighted in red do not match reference row.');
+                }
+                finishJSTest();
             }
         </script>
     </body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/alternate.css b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/alternate.css
deleted file mode 100644
index 0ea6d22..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/alternate.css
+++ /dev/null
@@ -1 +0,0 @@
-.testdiv{ background-color: red }
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-anon-script.js b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-anon-script.js
deleted file mode 100644
index 8493585f1..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-anon-script.js
+++ /dev/null
@@ -1 +0,0 @@
-crossorigin_anon_script=true;
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-anon-script.js.headers b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-anon-script.js.headers
deleted file mode 100644
index cb762eff..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-anon-script.js.headers
+++ /dev/null
@@ -1 +0,0 @@
-Access-Control-Allow-Origin: *
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-anon-style.css b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-anon-style.css
deleted file mode 100644
index 3cde4df..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-anon-style.css
+++ /dev/null
@@ -1 +0,0 @@
-.testdiv{ background-color: yellow }
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-anon-style.css.headers b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-anon-style.css.headers
deleted file mode 100644
index cb762eff..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-anon-style.css.headers
+++ /dev/null
@@ -1 +0,0 @@
-Access-Control-Allow-Origin: *
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-creds-script.js b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-creds-script.js
deleted file mode 100644
index 6f39e25..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-creds-script.js
+++ /dev/null
@@ -1 +0,0 @@
-crossorigin_creds_script=true;
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-creds-script.js.sub.headers b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-creds-script.js.sub.headers
deleted file mode 100644
index cf16bd8..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-creds-script.js.sub.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Access-Control-Allow-Origin: {{location[scheme]}}://{{domains[]}}:{{location[port]}}
-Access-Control-Allow-Credentials: true
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-creds-style.css b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-creds-style.css
deleted file mode 100644
index 3cde4df..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-creds-style.css
+++ /dev/null
@@ -1 +0,0 @@
-.testdiv{ background-color: yellow }
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-creds-style.css.sub.headers b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-creds-style.css.sub.headers
deleted file mode 100644
index cf16bd8..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-creds-style.css.sub.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Access-Control-Allow-Origin: {{location[scheme]}}://{{domains[]}}:{{location[port]}}
-Access-Control-Allow-Credentials: true
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-ineligible-script.js b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-ineligible-script.js
deleted file mode 100644
index dd2f968..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-ineligible-script.js
+++ /dev/null
@@ -1 +0,0 @@
-crossorigin_ineligible_script=true;
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-ineligible-style.css b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-ineligible-style.css
deleted file mode 100644
index 3cde4df..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/crossorigin-ineligible-style.css
+++ /dev/null
@@ -1 +0,0 @@
-.testdiv{ background-color: yellow }
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/matching-digest.js b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/matching-digest.js
deleted file mode 100644
index ec41325e..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/matching-digest.js
+++ /dev/null
@@ -1 +0,0 @@
-matching_digest=true;
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/non-matching-digest.js b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/non-matching-digest.js
deleted file mode 100644
index 1b4943e..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/non-matching-digest.js
+++ /dev/null
@@ -1 +0,0 @@
-non_matching_digest=true;
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/style.css b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/style.css
deleted file mode 100644
index 3cde4df..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/style.css
+++ /dev/null
@@ -1 +0,0 @@
-.testdiv{ background-color: yellow }
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/subresource-integrity.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/subresource-integrity.html
deleted file mode 100644
index 3dcd94a..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/subresource-integrity/subresource-integrity.html
+++ /dev/null
@@ -1,545 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Subresource Integrity</title>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-
-<div id="log"></div>
-
-<div id="container"></div>
-<script>
-    // <script> tests
-    var xorigin_anon_script = location.protocol
-      + '//www1.' + location.hostname + ':' + location.port
-      + '/subresource-integrity/crossorigin-anon-script.js';
-
-    var xorigin_creds_script = location.protocol
-      + '//www1.' + location.hostname + ':' + location.port
-      + '/subresource-integrity/crossorigin-creds-script.js';
-
-    var xorigin_ineligible_script = location.protocol
-      + '//www1.' + location.hostname + ':' + location.port
-      + '/subresource-integrity/crossorigin-ineligible-script.js';
-
-    var SRIScriptTest = function(pass, name, src, integrityValue, crossoriginValue) {
-        this.pass = pass;
-        this.name = "Script: " + name;
-        this.src = src;
-        this.integrityValue = integrityValue;
-        this.crossoriginValue = crossoriginValue;
-    }
-
-    SRIScriptTest.prototype.execute = function() {
-        var test = async_test(this.name);
-        var e = document.createElement("script");
-        e.src = this.src;
-        e.setAttribute("integrity", this.integrityValue);
-        if(this.crossoriginValue) {
-            e.setAttribute("crossorigin", this.crossoriginValue);
-        }
-        if(this.pass) {
-            e.addEventListener("load", function() {test.done()});
-            e.addEventListener("error", function() {
-                test.step(function(){ assert_unreached("Good load fired error handler.") })
-            });
-        } else {
-           e.addEventListener("load", function() {
-                test.step(function() { assert_unreached("Bad load succeeded.") })
-            });
-           e.addEventListener("error", function() {test.done()});
-        }
-        document.body.appendChild(e);
-    };
-
-    var xorigin_anon_style = location.protocol
-      + '//www1.' + location.hostname + ':' + location.port
-      + '/subresource-integrity/crossorigin-anon-style.css';
-
-    var xorigin_creds_style = location.protocol
-      + '//www1.' + location.hostname + ':' + location.port
-      + '/subresource-integrity/crossorigin-creds-style.css';
-
-    var xorigin_ineligible_style = location.protocol
-      + '//www1.' + location.hostname + ':' + location.port
-      + '/subresource-integrity/crossorigin-ineligible-style.css';
-
-    // <link> tests
-    // Style tests must be done synchronously because they rely on the presence
-    // and absence of global style, which can affect later tests. Thus, instead
-    // of executing them one at a time, the style tests are implemented as a
-    // queue that builds up a list of tests, and then executes them one at a
-    // time.
-    var SRIStyleTest = function(queue, pass, name, attrs, customCallback, altPassValue) {
-        this.pass = pass;
-        this.name = "Style: " + name;
-        this.customCallback = customCallback || function () {};
-        this.attrs = attrs || {};
-        this.passValue = altPassValue || "rgb(255, 255, 0)";
-
-        this.test = async_test(this.name);
-
-        this.queue = queue;
-        this.queue.push(this);
-    }
-
-    SRIStyleTest.prototype.execute = function() {
-        var that = this;
-        var container = document.getElementById("container");
-        while (container.hasChildNodes()) {
-          container.removeChild(container.firstChild);
-        }
-
-        var test = this.test;
-
-        var div = document.createElement("div");
-        div.className = "testdiv";
-        var e = document.createElement("link");
-        this.attrs.rel = this.attrs.rel || "stylesheet";
-        for (var key in this.attrs) {
-            if (this.attrs.hasOwnProperty(key)) {
-                e.setAttribute(key, this.attrs[key]);
-            }
-        }
-
-        if(this.pass) {
-            e.addEventListener("load", function() {
-                test.step(function() {
-                    var background = window.getComputedStyle(div, null).getPropertyValue("background-color");
-                    assert_equals(background, that.passValue);
-                    test.done();
-                });
-            });
-            e.addEventListener("error", function() {
-                test.step(function(){ assert_unreached("Good load fired error handler.") })
-            });
-        } else {
-            e.addEventListener("load", function() {
-                 test.step(function() { assert_unreached("Bad load succeeded.") })
-             });
-            e.addEventListener("error", function() {
-                test.step(function() {
-                    var background = window.getComputedStyle(div, null).getPropertyValue("background-color");
-                    assert_not_equals(background, that.passValue);
-                    test.done();
-                });
-            });
-        }
-        container.appendChild(div);
-        container.appendChild(e);
-        this.customCallback(e, container);
-    };
-
-    var style_tests = [];
-    style_tests.execute = function() {
-        if (this.length > 0) {
-            this.shift().execute();
-        }
-    }
-    add_result_callback(function(res) {
-        if (res.name.startsWith("Style: ")) {
-          style_tests.execute();
-        }
-    });
-
-    // Script tests
-    new SRIScriptTest(
-        true,
-        "Same-origin with correct sha256 hash.",
-        "matching-digest.js",
-        "sha256-U9WYDtBWkcHx13+9UKk/3Q5eoqDc4YGxYb07EPWzb9E="
-    ).execute();
-
-    new SRIScriptTest(
-        true,
-        "Same-origin with correct sha384 hash.",
-        "matching-digest.js",
-        "sha384-BDRTPSywZFyxfLEAzaLcL4FfERBgJgXfEkuT0r04LG93Yqn1PWNYPZMomaqEfE3H"
-    ).execute();
-
-    new SRIScriptTest(
-        true,
-        "Same-origin with correct sha512 hash.",
-        "matching-digest.js",
-        "sha512-geByvIIRspbnUnwooKGNNCb39nvg+EW0O9hDScTXeo/9pVZztLSUYU3LNV6H0lZapo8bCJUpyPPLAzE9fDzpxg=="
-    ).execute();
-
-    new SRIScriptTest(
-        true,
-        "Same-origin with empty integrity.",
-        "matching-digest.js",
-        ""
-    ).execute();
-
-    new SRIScriptTest(
-        false,
-        "Same-origin with incorrect hash.",
-        "non-matching-digest.js",
-        "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
-    ).execute();
-
-    new SRIScriptTest(
-        true,
-        "Same-origin with multiple sha256 hashes, including correct.",
-        "matching-digest.js",
-        "sha256-U9WYDtBWkcHx13+9UKk/3Q5eoqDc4YGxYb07EPWzb9E= sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
-    ).execute();
-
-    new SRIScriptTest(
-        true,
-        "Same-origin with multiple sha256 hashes, including unknown algorithm.",
-        "matching-digest.js",
-        "sha256-U9WYDtBWkcHx13+9UKk/3Q5eoqDc4YGxYb07EPWzb9E= foo666-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
-    ).execute();
-
-    new SRIScriptTest(
-        true,
-        "Same-origin with sha256 mismatch, sha512 match",
-        "matching-digest.js",
-        "sha512-geByvIIRspbnUnwooKGNNCb39nvg+EW0O9hDScTXeo/9pVZztLSUYU3LNV6H0lZapo8bCJUpyPPLAzE9fDzpxg== sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
-    ).execute();
-
-    new SRIScriptTest(
-        false,
-        "Same-origin with sha256 match, sha512 mismatch",
-        "matching-digest.js",
-        "sha512-deadbeefspbnUnwooKGNNCb39nvg+EW0O9hDScTXeo/9pVZztLSUYU3LNV6H0lZapo8bCJUpyPPLAzE9fDzpxg== sha256-U9WYDtBWkcHx13+9UKk/3Q5eoqDc4YGxYb07EPWzb9E="
-    ).execute();
-
-    new SRIScriptTest(
-        true,
-        "<crossorigin='anonymous'> with correct hash, ACAO: *",
-        xorigin_anon_script,
-        "sha256-51AjITq701Y0yKSx3/UoIKtIY2UQ9+H8WGyyMuOWOC0=",
-        "anonymous"
-    ).execute();
-
-    new SRIScriptTest(
-        false,
-        "<crossorigin='anonymous'> with incorrect hash, ACAO: *",
-        xorigin_anon_script,
-        "sha256-deadbeefcSLlbFZCj1OACLxTxVck2TOrBTEdUbwz1yU=",
-        "anonymous"
-    ).execute();
-
-    new SRIScriptTest(
-        true,
-        "<crossorigin='use-credentials'> with correct hash, CORS-eligible",
-        xorigin_creds_script,
-        "sha256-IaGApVboXPQxVSm2wVFmhMq1Yu37gWklajgMdxKLIvc=",
-        "use-credentials"
-    ).execute();
-
-    new SRIScriptTest(
-        false,
-        "<crossorigin='use-credentials'> with incorrect hash CORS-eligible",
-        xorigin_creds_script,
-        "sha256-deadbeef2S+pTRZgiw3DWrhC6JLDlt2zRyGpwH7unU8=",
-        "use-credentials"
-    ).execute();
-
-    new SRIScriptTest(
-        false,
-        "<crossorigin='anonymous'> with CORS-ineligible resource",
-        xorigin_ineligible_script,
-        "sha256-F5fXKTX7SiWjtgybxiBZIo2qhh2WiQnNx372E60XrOo=",
-        "anonymous"
-    ).execute();
-
-    new SRIScriptTest(
-        false,
-        "Cross-origin, not CORS request, with correct hash",
-        xorigin_anon_script,
-        "sha256-51AjITq701Y0yKSx3/UoIKtIY2UQ9+H8WGyyMuOWOC0="
-    ).execute();
-
-    new SRIScriptTest(
-        false,
-        "Cross-origin, not CORS request, with hash mismatch",
-        xorigin_anon_script,
-        "sha256-deadbeef01Y0yKSx3/UoIKtIY2UQ9+H8WGyyMuOWOC0="
-    ).execute();
-
-    new SRIScriptTest(
-        true,
-        "Cross-origin, empty integrity",
-        xorigin_anon_script,
-        ""
-    ).execute();
-
-    new SRIScriptTest(
-        true,
-        "Same-origin with correct hash, options.",
-        "matching-digest.js",
-        "sha256-U9WYDtBWkcHx13+9UKk/3Q5eoqDc4YGxYb07EPWzb9E=?foo=bar?spam=eggs"
-    ).execute();
-
-    new SRIScriptTest(
-        true,
-        "Same-origin with unknown algorithm only.",
-        "matching-digest.js",
-        "foo666-U9WYDtBWkcHx13+9UKk/3Q5eoqDc4YGxYb07EPWzb9E="
-    ).execute();
-
-    // Style tests
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Same-origin with correct sha256 hash",
-        {
-            href: "style.css?1",
-            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4="
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Same-origin with correct sha384 hash",
-        {
-            href: "style.css?2",
-            integrity: "sha384-wDAWxH4tOWBwAwHfBn9B7XuNmFxHTMeigAMwn0iVQ0zq3FtmYMLxihcGnU64CwcX"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Same-origin with correct sha512 hash",
-        {
-            href: "style.css?3",
-            integrity: "sha512-9wXDjd6Wq3H6nPAhI9zOvG7mJkUr03MTxaO+8ztTKnfJif42laL93Be/IF6YYZHHF4esitVYxiwpY2HSZX4l6w=="
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Same-origin with empty integrity",
-        {
-            href: "style.css?4",
-            integrity: ""
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        false,
-        "Same-origin with incorrect hash.",
-        {
-            href: "style.css?5",
-            integrity: "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Same-origin with multiple sha256 hashes, including correct.",
-        {
-            href: "style.css?6",
-            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4= sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Same-origin with multiple sha256 hashes, including unknown algorithm.",
-        {
-            href: "style.css?7",
-            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4= foo666-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Same-origin with sha256 mismatch, sha512 match",
-        {
-            href: "style.css?8",
-            integrity: "sha512-9wXDjd6Wq3H6nPAhI9zOvG7mJkUr03MTxaO+8ztTKnfJif42laL93Be/IF6YYZHHF4esitVYxiwpY2HSZX4l6w== sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        false,
-        "Same-origin with sha256 match, sha512 mismatch",
-        {
-            href: "style.css?9",
-            integrity: "sha512-deadbeef9wXDjd6Wq3H6nPAhI9zOvG7mJkUr03MTxaO+8ztTKnfJif42laL93Be/IF6YYZHHF4esitVYxiwpY2== sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4="
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "<crossorigin='anonymous'> with correct hash, ACAO: *",
-        {
-            href: xorigin_anon_style + '?1',
-            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
-            crossorigin: "anonymous"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        false,
-        "<crossorigin='anonymous'> with incorrect hash, ACAO: *",
-        {
-            href: xorigin_anon_style + '?2',
-            integrity: "sha256-deadbeefCzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk=",
-            crossorigin: "anonymous"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "<crossorigin='use-credentials'> with correct hash, CORS-eligible",
-        {
-            href: xorigin_creds_style + '?1',
-            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
-            crossorigin: "use-credentials"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        false,
-        "<crossorigin='use-credentials'> with incorrect hash CORS-eligible",
-        {
-            href: xorigin_creds_style + '?2',
-            integrity: "sha256-deadbeefCzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk=",
-            crossorigin: "use-credentials"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        false,
-        "<crossorigin='anonymous'> with CORS-ineligible resource",
-        {
-            href: xorigin_ineligible_style + '?1',
-            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
-            crossorigin: "anonymous"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        false,
-        "Cross-origin, not CORS request, with correct hash",
-        {
-            href: xorigin_anon_style + '?3',
-            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4="
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        false,
-        "Cross-origin, not CORS request, with hash mismatch",
-        {
-            href: xorigin_anon_style + '?4',
-            integrity: "sha256-deadbeefCzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk="
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Cross-origin, empty integrity",
-        {
-            href: xorigin_anon_style + '?5',
-            integrity: ""
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Same-origin with correct hash, options.",
-        {
-            href: "style.css?10",
-            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=?foo=bar?spam=eggs"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Same-origin with unknown algorithm only.",
-        {
-            href: "style.css?11",
-            integrity: "foo666-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=?foo=bar?spam=eggs"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Same-origin with correct sha256 hash, rel='stylesheet license'",
-        {
-            href: "style.css?12",
-            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
-            rel: "stylesheet license"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Same-origin with correct sha256 hash, rel='license stylesheet'",
-        {
-            href: "style.css?13",
-            integrity: "sha256-CzHgdJ7wOccM8L89n4bhcJMz3F+SPLT7YZk7gyCWUV4=",
-            rel: "license stylesheet"
-        }
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        true,
-        "Same-origin with correct sha256 and sha512 hash, rel='alternate stylesheet' enabled",
-        {
-            href: "alternate.css?1",
-            title: "alt",
-            type: "text/css",
-            class: "alternate",
-            disabled: "disabled",
-            rel: "alternate stylesheet",
-            integrity: "sha256-phbz83bWhnLig+d2VPKrRrTRyhqoDRo1ruGqZLZ0= sha512-8OYEB7ktnzcb6h+kB9CUIuc8qvKIyLpygRJdQSEEycRy74dUsB+Yu9rSjpOPjRUblle8WWX9Gn7v39LK2Oceig==",
-        },
-        function (link, container) {
-            var alternate = document.querySelector('link.alternate');
-            alternate.disabled = false;
-        },
-        "rgb(255, 0, 0)"
-    );
-
-    new SRIStyleTest(
-        style_tests,
-        false,
-        "Same-origin with incorrect sha256 and sha512 hash, rel='alternate stylesheet' enabled",
-        {
-            href: "alternate.css?2",
-            title: "alt",
-            type: "text/css",
-            class: "alternate",
-            disabled: "disabled",
-            rel: "alternate stylesheet",
-            integrity: "sha256-fail83bWhnLig+d2VPKrRrTRyhqoDRo1ruGqZLZ0= sha512-failB7ktnzcb6h+kB9CUIuc8qvKIyLpygRJdQSEEycRy74dUsB+Yu9rSjpOPjRUblle8WWX9Gn7v39LK2Oceig==",
-        },
-        function (link, container) {
-            var alternate = document.querySelector('link.alternate');
-            alternate.disabled = false;
-        }
-    );
-
-    style_tests.execute();
-
-</script>
-<!-- TODO check cache-poisoned resources, transfer-encoding, 3xx redirect
-   to resource with matching hash, and cross-origin leakage test as in sec5.3.
-    -->
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships-expected.txt
index 825de93..7f12afa4 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships-expected.txt
@@ -34,17 +34,19 @@
           "name": "activedescendant",
           "value": {
             "type": "idref",
-            "relatedNodeValue": {
-              "idref": "rg1-r4",
-              "nodeResult": "li#rg1-r4"
-            }
+            "relatedNodes": [
+              {
+                "idref": "rg1-r4",
+                "nodeResult": "li#rg1-r4"
+              }
+            ]
           }
         },
         {
           "name": "labelledby",
           "value": {
             "type": "idrefList",
-            "relatedNodeArrayValue": [
+            "relatedNodes": [
               {
                 "idref": "rg1_label",
                 "nodeResult": "h3#rg1_label"
@@ -62,7 +64,7 @@
             "type": "relatedElement",
             "value": {
               "type": "idrefList",
-              "relatedNodeArrayValue": [
+              "relatedNodes": [
                 {
                   "idref": "rg1_label",
                   "text": "Lunch Options",
@@ -114,7 +116,7 @@
           "name": "labelledby",
           "value": {
             "type": "idrefList",
-            "relatedNodeArrayValue": [
+            "relatedNodes": [
               {
                 "idref": "rg2_label",
                 "nodeResult": "h3#rg2_label"
@@ -132,7 +134,7 @@
             "type": "relatedElement",
             "value": {
               "type": "idrefList",
-              "relatedNodeArrayValue": [
+              "relatedNodes": [
                 {
                   "idref": "rg2_label",
                   "text": "Drink Options",
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships.html b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships.html
index 39b0239..0b89b4e 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships.html
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships.html
@@ -101,17 +101,13 @@
 
     function rewriteValue(value, promises)
     {
-        if (value.type === "idrefList") {
-            checkExists("relatedNodeArrayValue", value);
-            var relatedNodeArray = value.relatedNodeArrayValue;
-            check(Array.isArray(relatedNodeArray), "relatedNodeArrayValue should be an array", JSON.stringify(value));
+        if (value.type === "idrefList" || value.type === "idref") {
+            checkExists("relatedNodes", value);
+            var relatedNodeArray = value.relatedNodes;
+            check(Array.isArray(relatedNodeArray), "relatedNodes should be an array", JSON.stringify(value));
             for (var relatedNode of relatedNodeArray) {
                promises.push(rewriteNode(relatedNode));
             }
-        } else if (value.type === "idref") {
-           checkExists("relatedNodeValue", value);
-           var relatedNode = value.relatedNodeValue;
-           promises.push(rewriteNode(relatedNode));
         }
     }
     function rewriteNodes(msg)
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt
index 640ea0f..d933c02 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt
@@ -116,9 +116,11 @@
           "name": "ancestorDisallowsChild",
           "value": {
             "type": "idref",
-            "relatedNodeValue": {
-              "backendNodeId": "<string>"
-            }
+            "relatedNodes": [
+              {
+                "backendNodeId": "<string>"
+              }
+            ]
           }
         }
       ]
@@ -140,9 +142,11 @@
           "name": "ancestorDisallowsChild",
           "value": {
             "type": "idref",
-            "relatedNodeValue": {
-              "backendNodeId": "<string>"
-            }
+            "relatedNodes": [
+              {
+                "backendNodeId": "<string>"
+              }
+            ]
           }
         }
       ]
@@ -164,9 +168,11 @@
           "name": "ancestorIsLeafNode",
           "value": {
             "type": "idref",
-            "relatedNodeValue": {
-              "backendNodeId": "<string>"
-            }
+            "relatedNodes": [
+              {
+                "backendNodeId": "<string>"
+              }
+            ]
           }
         }
       ]
@@ -210,10 +216,12 @@
           "name": "ariaHiddenRoot",
           "value": {
             "type": "idref",
-            "relatedNodeValue": {
-              "backendNodeId": "<string>",
-              "idref": "_6"
-            }
+            "relatedNodes": [
+              {
+                "backendNodeId": "<string>",
+                "idref": "_6"
+              }
+            ]
           }
         }
       ]
@@ -298,10 +306,12 @@
           "name": "inheritsPresentation",
           "value": {
             "type": "idref",
-            "relatedNodeValue": {
-              "backendNodeId": "<string>",
-              "idref": "_9"
-            }
+            "relatedNodes": [
+              {
+                "backendNodeId": "<string>",
+                "idref": "_9"
+              }
+            ]
           }
         }
       ]
@@ -355,10 +365,12 @@
           "name": "labelFor",
           "value": {
             "type": "idref",
-            "relatedNodeValue": {
-              "backendNodeId": "<string>",
-              "idref": "checkbox"
-            }
+            "relatedNodes": [
+              {
+                "backendNodeId": "<string>",
+                "idref": "checkbox"
+              }
+            ]
           }
         }
       ]
@@ -380,20 +392,24 @@
           "name": "labelContainer",
           "value": {
             "type": "idref",
-            "relatedNodeValue": {
-              "backendNodeId": "<string>",
-              "idref": "_12"
-            }
+            "relatedNodes": [
+              {
+                "backendNodeId": "<string>",
+                "idref": "_12"
+              }
+            ]
           }
         },
         {
           "name": "labelFor",
           "value": {
             "type": "idref",
-            "relatedNodeValue": {
-              "backendNodeId": "<string>",
-              "idref": "checkbox"
-            }
+            "relatedNodes": [
+              {
+                "backendNodeId": "<string>",
+                "idref": "checkbox"
+              }
+            ]
           }
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesModal-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesModal-expected.txt
index fc7eb82..e53ea7e0 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesModal-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesModal-expected.txt
@@ -16,10 +16,12 @@
           "name": "activeModalDialog",
           "value": {
             "type": "idref",
-            "relatedNodeValue": {
-              "backendNodeId": "<string>",
-              "idref": "_2"
-            }
+            "relatedNodes": [
+              {
+                "backendNodeId": "<string>",
+                "idref": "_2"
+              }
+            ]
           }
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesTest.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesTest.js
index 6f814b8..34297f7 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesTest.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesTest.js
@@ -136,18 +136,13 @@
         }
         var promises = [];
         for (var property of properties) {
-            if (property.value.type === "idrefList") {
-                if (!InspectorTest._checkExists("value.relatedNodeArrayValue", property, reject))
+            if (property.value.type === "idrefList" || property.value.type === "idref") {
+                if (!InspectorTest._checkExists("value.relatedNodes", property, reject))
                     return;
-                var relatedNodeArray = property.value.relatedNodeArrayValue;
-                InspectorTest._check(Array.isArray(relatedNodeArray), "value.relatedNodeArrayValue should be an array", JSON.stringify(property), reject);
+                var relatedNodeArray = property.value.relatedNodes;
+                InspectorTest._check(Array.isArray(relatedNodeArray), "value.relatedNodes should be an array", JSON.stringify(property), reject);
                  for (var relatedNode of relatedNodeArray)
                      promises.push(InspectorTest._rewriteNode(relatedNode));
-            } else if (property.value.type === "idref") {
-                if (!InspectorTest._checkExists("value.relatedNodeValue", property, reject))
-                    return;
-                var relatedNode = property.value.relatedNodeValue;
-                promises.push(InspectorTest._rewriteNode(relatedNode));
             }
         }
 
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-object-preview-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-object-preview-expected.txt
index 2929ca4..15ba330 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-object-preview-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-object-preview-expected.txt
@@ -36,22 +36,22 @@
 console-object-preview.html:20 [0, 0, 1] console-message-text source-code > console-message-url webkit-html-resource-link > object-value-array source-code > console-object-preview > object-value-number > object-value-number > object-value-number
 console-object-preview.html:20 [0, 0, 2] console-message-text source-code > console-message-url webkit-html-resource-link > object-value-array source-code > console-object-preview > object-value-number > object-value-number > object-value-number
 console-object-preview.html:23 Object with many properties console-message-text source-code > console-message-url webkit-html-resource-link
-console-object-preview.html:28 Object {property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4…} console-message-text source-code > console-message-url webkit-html-resource-link > object-value-object source-code > console-view-object-properties-section > tree-outline source-code object-properties-section > parent > selection > console-object-preview > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > object-info-state-note > children
+console-object-preview.html:28 Object {property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4…} console-message-text source-code > console-message-url webkit-html-resource-link > object-value-object source-code > console-view-object-properties-section > tree-outline source-code object-properties-section > parent > selection fill > console-object-preview > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > object-info-state-note > children
 console-object-preview.html:30 Array with many properties console-message-text source-code > console-message-url webkit-html-resource-link
-console-object-preview.html:35 [0, 1, property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4…] console-message-text source-code > console-message-url webkit-html-resource-link > object-value-array source-code > console-view-object-properties-section > tree-outline source-code object-properties-section > parent > selection > console-object-preview > object-value-number > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > object-info-state-note > children
+console-object-preview.html:35 [0, 1, property_0: 0, property_1: 1, property_2: 2, property_3: 3, property_4: 4…] console-message-text source-code > console-message-url webkit-html-resource-link > object-value-array source-code > console-view-object-properties-section > tree-outline source-code object-properties-section > parent > selection fill > console-object-preview > object-value-number > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > object-info-state-note > children
 console-object-preview.html:37 Object with proto console-message-text source-code > console-message-url webkit-html-resource-link
-console-object-preview.html:40 Object {d: 1} console-message-text source-code > console-message-url webkit-html-resource-link > object-value-object source-code > console-view-object-properties-section > tree-outline source-code object-properties-section > parent > selection > console-object-preview > name > object-value-number > object-info-state-note > children
+console-object-preview.html:40 Object {d: 1} console-message-text source-code > console-message-url webkit-html-resource-link > object-value-object source-code > console-view-object-properties-section > tree-outline source-code object-properties-section > parent > selection fill > console-object-preview > name > object-value-number > object-info-state-note > children
 console-object-preview.html:42 Sparse array console-message-text source-code > console-message-url webkit-html-resource-link
 console-object-preview.html:45 [50: 50] console-message-text source-code > console-message-url webkit-html-resource-link > object-value-array source-code > console-object-preview > name > object-value-number
 console-object-preview.html:47 Dense array with indexes and propeties console-message-text source-code > console-message-url webkit-html-resource-link
-console-object-preview.html:53 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99…] console-message-text source-code > console-message-url webkit-html-resource-link > object-value-array source-code > console-view-object-properties-section > tree-outline source-code object-properties-section > parent > selection > console-object-preview > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-info-state-note > children
+console-object-preview.html:53 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99…] console-message-text source-code > console-message-url webkit-html-resource-link > object-value-array source-code > console-view-object-properties-section > tree-outline source-code object-properties-section > parent > selection fill > console-object-preview > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-value-number > object-info-state-note > children
 console-object-preview.html:55 Object with properties containing whitespaces console-message-text source-code > console-message-url webkit-html-resource-link
 console-object-preview.html:62 Object {" a b ": " a b ", c d: "c d", "": "", "  ": "  ", "a↵↵b↵c": "a↵↵b↵c"} console-message-text source-code > console-message-url webkit-html-resource-link > object-value-object source-code > console-object-preview > name > object-value-string > name > object-value-string > name > object-value-string > name > object-value-string > name > object-value-string
 console-object-preview.html:64 Object with a document.all property console-message-text source-code > console-message-url webkit-html-resource-link
-console-object-preview.html:65 Object {all: HTMLAllCollection[7]} console-message-text source-code > console-message-url webkit-html-resource-link > object-value-object source-code > console-view-object-properties-section > tree-outline source-code object-properties-section > parent > selection > console-object-preview > name > object-value-array > object-info-state-note > children
+console-object-preview.html:65 Object {all: HTMLAllCollection[7]} console-message-text source-code > console-message-url webkit-html-resource-link > object-value-object source-code > console-view-object-properties-section > tree-outline source-code object-properties-section > parent > selection fill > console-object-preview > name > object-value-array > object-info-state-note > children
 console-object-preview.html:67 Object with special numbers console-message-text source-code > console-message-url webkit-html-resource-link
 console-object-preview.html:69 Object {nan: NaN, posInf: Infinity, negInf: -Infinity, negZero: -0} console-message-text source-code > console-message-url webkit-html-resource-link > object-value-object source-code > console-object-preview > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number
 console-object-preview.html:71 Object with exactly 5 properties: expected to be lossless console-message-text source-code > console-message-url webkit-html-resource-link
 console-object-preview.html:72 Object {a: 1, b: 2, c: 3, d: 4, e: 5} console-message-text source-code > console-message-url webkit-html-resource-link > object-value-object source-code > console-object-preview > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number > name > object-value-number
-console-object-preview.html:74 Object {null: null, undef: undefined, regexp: /^[regexp]$/g, bool: false} console-message-text source-code > console-message-url webkit-html-resource-link > object-value-object source-code > console-view-object-properties-section > tree-outline source-code object-properties-section > parent > selection > console-object-preview > name > object-value-null > name > object-value-undefined > name > object-value-regexp > name > object-value-boolean > object-info-state-note > children
+console-object-preview.html:74 Object {null: null, undef: undefined, regexp: /^[regexp]$/g, bool: false} console-message-text source-code > console-message-url webkit-html-resource-link > object-value-object source-code > console-view-object-properties-section > tree-outline source-code object-properties-section > parent > selection fill > console-object-preview > name > object-value-null > name > object-value-undefined > name > object-value-regexp > name > object-value-boolean > object-info-state-note > children
 
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index 5e3ab20..d9f411d5 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -1769,6 +1769,9 @@
             'inspector/v8/V8InjectedScriptHost.h',
             'inspector/v8/V8JavaScriptCallFrame.cpp',
             'inspector/v8/V8JavaScriptCallFrame.h',
+            'inspector/v8/V8ProfilerAgent.h',
+            'inspector/v8/V8ProfilerAgentImpl.cpp',
+            'inspector/v8/V8ProfilerAgentImpl.h',
             'inspector/v8/V8RuntimeAgent.h',
             'inspector/v8/V8RuntimeAgentImpl.cpp',
             'inspector/v8/V8RuntimeAgentImpl.h',
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
index 36251dd7..69d4867 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -77,9 +77,8 @@
 #if !ENABLE(OILPAN)
 void ContainerNode::removeDetachedChildren()
 {
-    // TODO(bokan): Temporarily made RELEASE_ASSERT to trackdown crbug.com/519752.
-    RELEASE_ASSERT(!connectedSubframeCount());
-    RELEASE_ASSERT(needsAttach());
+    ASSERT(!connectedSubframeCount());
+    ASSERT(needsAttach());
     removeDetachedChildrenInContainer(*this);
 }
 #endif
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 9fa9677..122c84f7 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -2143,7 +2143,7 @@
 void Document::detach(const AttachContext& context)
 {
     TRACE_EVENT0("blink", "Document::detach");
-    ASSERT(!m_frame || m_frame->tree().childCount() == 0);
+    RELEASE_ASSERT(!m_frame || m_frame->tree().childCount() == 0);
     if (!isActive())
         return;
 
@@ -2244,6 +2244,9 @@
     // created by DOMImplementation::createDocument().
     DocumentLifecycleNotifier::notifyContextDestroyed();
     ExecutionContext::notifyContextDestroyed();
+
+    // TODO(bokan): Temporarily added this RELEASE_ASSERT to trackdown crbug.com/519752.
+    RELEASE_ASSERT(!connectedSubframeCount());
 }
 
 void Document::removeAllEventListeners()
diff --git a/third_party/WebKit/Source/core/dom/Fullscreen.cpp b/third_party/WebKit/Source/core/dom/Fullscreen.cpp
index 46c01d3..bc34c3f 100644
--- a/third_party/WebKit/Source/core/dom/Fullscreen.cpp
+++ b/third_party/WebKit/Source/core/dom/Fullscreen.cpp
@@ -69,7 +69,7 @@
     return !document.settings() || document.settings()->fullscreenSupported();
 }
 
-static bool fullscreenElementReady(const Element& element, Fullscreen::RequestType requestType)
+static bool fullscreenElementReady(const Element& element)
 {
     // A fullscreen element ready check for an element |element| returns true if all of the
     // following are true, and false otherwise:
@@ -98,7 +98,7 @@
     // fullscreen element ready check returns true for |element|'s node document's browsing
     // context's browsing context container, or it has no browsing context container.
     if (const Element* owner = element.document().ownerElement()) {
-        if (!fullscreenElementReady(*owner, requestType))
+        if (!fullscreenElementReady(*owner))
             return false;
     }
 
@@ -223,7 +223,7 @@
         // node document:
 
         // The fullscreen element ready check returns false.
-        if (!fullscreenElementReady(element, requestType))
+        if (!fullscreenElementReady(element))
             break;
 
         // This algorithm is not allowed to show a pop-up:
@@ -246,15 +246,15 @@
         Document* currentDoc = document();
 
         // 3. Let docs be all doc's ancestor browsing context's documents (if any) and doc.
-        Deque<Document*> docs;
+        WillBeHeapDeque<RawPtrWillBeMember<Document>> docs;
 
         do {
             docs.prepend(currentDoc);
-            currentDoc = currentDoc->ownerElement() ? &currentDoc->ownerElement()->document() : 0;
+            currentDoc = currentDoc->ownerElement() ? &currentDoc->ownerElement()->document() : nullptr;
         } while (currentDoc);
 
         // 4. For each document in docs, run these substeps:
-        Deque<Document*>::iterator current = docs.begin(), following = docs.begin();
+        WillBeHeapDeque<RawPtrWillBeMember<Document>>::iterator current = docs.begin(), following = docs.begin();
 
         do {
             ++following;
@@ -262,7 +262,7 @@
             // 1. Let following document be the document after document in docs, or null if there is no
             // such document.
             Document* currentDoc = *current;
-            Document* followingDoc = following != docs.end() ? *following : 0;
+            Document* followingDoc = following != docs.end() ? *following : nullptr;
 
             // 2. If following document is null, push context object on document's fullscreen element
             // stack, and queue a task to fire an event named fullscreenchange with its bubbles attribute
@@ -294,7 +294,7 @@
 
         // 7. Optionally, display a message indicating how the user can exit displaying the context object fullscreen.
         return;
-    } while (0);
+    } while (false);
 
     enqueueErrorEvent(element, requestType);
 }
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index 5356ecb..eff218e 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -217,6 +217,17 @@
     m_layoutSubtreeRootList.clear();
 }
 
+template <typename Function>
+void FrameView::forAllFrameViews(Function function)
+{
+    for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
+        if (!frame->isLocalFrame())
+            continue;
+        if (FrameView* view = toLocalFrame(frame)->view())
+            function(*view);
+    }
+}
+
 void FrameView::removeFromAXObjectCache()
 {
     if (AXObjectCache* cache = axObjectCache()) {
@@ -1270,14 +1281,9 @@
 
 void FrameView::scrollContentsIfNeededRecursive()
 {
-    scrollContentsIfNeeded();
-
-    for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
-        if (!child->isLocalFrame())
-            continue;
-        if (FrameView* view = toLocalFrame(child)->view())
-            view->scrollContentsIfNeededRecursive();
-    }
+    forAllFrameViews([](FrameView& frameView) {
+        frameView.scrollContentsIfNeeded();
+    });
 }
 
 bool FrameView::invalidateViewportConstrainedObjects()
@@ -1796,14 +1802,10 @@
 
 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
 {
-    for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
-        if (!frame->isLocalFrame())
-            continue;
-        if (FrameView* view = toLocalFrame(frame)->view()) {
-            view->setTransparent(transparent);
-            view->setBaseBackgroundColor(backgroundColor);
-        }
-    }
+    forAllFrameViews([backgroundColor, transparent](FrameView& frameView) {
+        frameView.setTransparent(transparent);
+        frameView.setBaseBackgroundColor(backgroundColor);
+    });
 }
 
 void FrameView::scrollToAnchor()
@@ -2453,9 +2455,9 @@
 {
     ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
 
-    lifecycle().advanceTo(DocumentLifecycle::InUpdatePaintProperties);
+    forAllFrameViews([](FrameView& frameView) { frameView.lifecycle().advanceTo(DocumentLifecycle::InUpdatePaintProperties); });
     // TODO(pdr): Calculate the paint properties by walking the layout tree.
-    lifecycle().advanceTo(DocumentLifecycle::UpdatePaintPropertiesClean);
+    forAllFrameViews([](FrameView& frameView) { frameView.lifecycle().advanceTo(DocumentLifecycle::UpdatePaintPropertiesClean); });
 }
 
 void FrameView::synchronizedPaint(const LayoutRect* interestRect)
@@ -2467,18 +2469,23 @@
     ASSERT(view);
     // TODO(chrishtr): figure out if there can be any GraphicsLayer above this one that draws content.
     GraphicsLayer* rootGraphicsLayer = view->layer()->graphicsLayerBacking();
-    lifecycle().advanceTo(DocumentLifecycle::InPaint);
+    forAllFrameViews([](FrameView& frameView) { frameView.lifecycle().advanceTo(DocumentLifecycle::InPaint); });
 
     // A null graphics layer can occur for painting of SVG images that are not parented into the main frame tree.
     if (rootGraphicsLayer) {
         synchronizedPaintRecursively(rootGraphicsLayer, interestRect);
     }
-    lifecycle().advanceTo(DocumentLifecycle::PaintClean);
+
+    forAllFrameViews([](FrameView& frameView) {
+        frameView.lifecycle().advanceTo(DocumentLifecycle::PaintClean);
+        frameView.layoutView()->layer()->clearNeedsRepaintRecursively();
+    });
 }
 
 void FrameView::synchronizedPaintRecursively(GraphicsLayer* graphicsLayer, const LayoutRect* interestRect)
 {
-    GraphicsContext context(graphicsLayer->paintController());
+    ASSERT(graphicsLayer->paintController());
+    GraphicsContext context(*graphicsLayer->paintController());
 
     // TODO(chrishtr): fix unit tests to not inject one-off interest rects.
     if (interestRect)
@@ -2489,10 +2496,8 @@
     if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled())
         graphicsLayer->paintController()->commitNewDisplayItems(graphicsLayer);
 
-    for (auto& child : graphicsLayer->children()) {
-        if (child)
-            synchronizedPaintRecursively(child, interestRect);
-    }
+    for (auto& child : graphicsLayer->children())
+        synchronizedPaintRecursively(child, interestRect);
 }
 
 void FrameView::compositeForSlimmingPaintV2()
@@ -2500,7 +2505,7 @@
     ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
     ASSERT(frame() == page()->mainFrame() || (!frame().tree().parent()->isLocalFrame()));
 
-    lifecycle().advanceTo(DocumentLifecycle::InCompositingForSlimmingPaintV2);
+    forAllFrameViews([](FrameView& frameView) { frameView.lifecycle().advanceTo(DocumentLifecycle::InCompositingForSlimmingPaintV2); });
 
     // Detached frames can have no root graphics layer.
     if (GraphicsLayer* rootGraphicsLayer = layoutView()->layer()->graphicsLayerBacking()) {
@@ -2512,7 +2517,7 @@
         page()->setCompositedDisplayList(compositedDisplayList.release());
     }
 
-    lifecycle().advanceTo(DocumentLifecycle::CompositingForSlimmingPaintV2Clean);
+    forAllFrameViews([](FrameView& frameView) { frameView.lifecycle().advanceTo(DocumentLifecycle::CompositingForSlimmingPaintV2Clean); });
 }
 
 void FrameView::updateFrameTimingRequestsIfNeeded()
@@ -2949,7 +2954,7 @@
     Page* page = frame().page();
     if (!page || !page->settings().deviceSupportsMouse())
         return;
-    page->chromeClient().setCursor(cursor);
+    page->chromeClient().setCursor(cursor, m_frame->localFrameRoot());
 }
 
 void FrameView::frameRectsChanged()
diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h
index ac44e9d8..a643ff8 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.h
+++ b/third_party/WebKit/Source/core/frame/FrameView.h
@@ -716,6 +716,8 @@
     void collectFrameTimingRequests(GraphicsLayerFrameTimingRequests&);
     void collectFrameTimingRequestsRecursive(GraphicsLayerFrameTimingRequests&);
 
+    template <typename Function> void forAllFrameViews(Function);
+
     LayoutSize m_size;
 
     typedef HashSet<RefPtr<LayoutEmbeddedObject>> EmbeddedObjectSet;
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index f9b4716..16caece 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -1979,7 +1979,7 @@
         if (m_userGestureRequiredForPlay) {
             recordAutoplayMetric(PlayMethodFailed);
             String message = ExceptionMessages::failedToExecute("play", "HTMLMediaElement", "API can only be initiated by a user gesture.");
-            document().executionContext()->addConsoleMessage(ConsoleMessage::create(JSMessageSource, WarningMessageLevel, message));
+            document().addConsoleMessage(ConsoleMessage::create(JSMessageSource, WarningMessageLevel, message));
             return;
         }
     } else if (m_userGestureRequiredForPlay) {
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
index e6cdcd7..fd9dda1f 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -42,6 +42,7 @@
 #include "core/events/GestureEvent.h"
 #include "core/events/KeyboardEvent.h"
 #include "core/events/MouseEvent.h"
+#include "core/events/ScopedEventQueue.h"
 #include "core/frame/FrameHost.h"
 #include "core/frame/FrameView.h"
 #include "core/frame/LocalFrame.h"
@@ -1705,24 +1706,27 @@
     if (!focused())
         accessKeyAction(false);
 
-    // If this index is already selected, unselect. otherwise update the selected index.
     const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& items = listItems();
     int listIndex = optionToListIndex(index);
-    if (listIndex >= 0) {
-        HTMLElement* element = items[listIndex];
-        if (isHTMLOptionElement(*element)) {
-            if (toHTMLOptionElement(*element).selected())
-                toHTMLOptionElement(*element).setSelectedState(false);
-            else
-                selectOption(index, DispatchInputAndChangeEvent | UserDriven);
-        }
+    if (listIndex < 0)
+        return;
+    HTMLElement& element = *items[listIndex];
+    if (!isHTMLOptionElement(element))
+        return;
+    EventQueueScope scope;
+    // If this index is already selected, unselect. otherwise update the
+    // selected index.
+    if (toHTMLOptionElement(element).selected()) {
+        if (usesMenuList())
+            selectOption(-1, DispatchInputAndChangeEvent | UserDriven);
+        else
+            toHTMLOptionElement(element).setSelectedState(false);
+    } else {
+        selectOption(index, DispatchInputAndChangeEvent | UserDriven);
     }
-
     if (usesMenuList())
-        dispatchInputAndChangeEventForMenuList();
-    else
-        listBoxOnChange();
-
+        return;
+    listBoxOnChange();
     scrollToSelection();
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.cpp
index 254e269..3321aef 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.cpp
@@ -33,134 +33,26 @@
 #include "bindings/core/v8/ScriptCallStackFactory.h"
 #include "bindings/core/v8/V8Binding.h"
 #include "core/frame/UseCounter.h"
-#include "core/inspector/InjectedScript.h"
-#include "core/inspector/InjectedScriptHost.h"
 #include "core/inspector/InspectorState.h"
 #include "core/inspector/InstrumentingAgents.h"
 #include "core/inspector/ScriptCallStack.h"
-#include <v8-profiler.h>
+#include "core/inspector/v8/V8ProfilerAgent.h"
 
 namespace blink {
 
 namespace ProfilerAgentState {
-static const char samplingInterval[] = "samplingInterval";
-static const char userInitiatedProfiling[] = "userInitiatedProfiling";
 static const char profilerEnabled[] = "profilerEnabled";
-static const char nextProfileId[] = "nextProfileId";
 }
 
-namespace {
-
-PassRefPtr<TypeBuilder::Array<TypeBuilder::Profiler::PositionTickInfo>> buildInspectorObjectForPositionTicks(const v8::CpuProfileNode* node)
+PassOwnPtrWillBeRawPtr<InspectorProfilerAgent> InspectorProfilerAgent::create(v8::Isolate* isolate, Client* client)
 {
-    RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::PositionTickInfo>> array = TypeBuilder::Array<TypeBuilder::Profiler::PositionTickInfo>::create();
-    unsigned lineCount = node->GetHitLineCount();
-    if (!lineCount)
-        return array.release();
-
-    Vector<v8::CpuProfileNode::LineTick> entries(lineCount);
-    if (node->GetLineTicks(&entries[0], lineCount)) {
-        for (unsigned i = 0; i < lineCount; i++) {
-            RefPtr<TypeBuilder::Profiler::PositionTickInfo> line = TypeBuilder::Profiler::PositionTickInfo::create()
-                .setLine(entries[i].line)
-                .setTicks(entries[i].hit_count);
-            array->addItem(line);
-        }
-    }
-
-    return array.release();
+    return adoptPtrWillBeNoop(new InspectorProfilerAgent(isolate, client));
 }
 
-PassRefPtr<TypeBuilder::Profiler::CPUProfileNode> buildInspectorObjectFor(const v8::CpuProfileNode* node)
-{
-    v8::HandleScope handleScope(v8::Isolate::GetCurrent());
-
-    RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>> children = TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>::create();
-    const int childrenCount = node->GetChildrenCount();
-    for (int i = 0; i < childrenCount; i++) {
-        const v8::CpuProfileNode* child = node->GetChild(i);
-        children->addItem(buildInspectorObjectFor(child));
-    }
-
-    RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::PositionTickInfo>> positionTicks = buildInspectorObjectForPositionTicks(node);
-
-    RefPtr<TypeBuilder::Profiler::CPUProfileNode> result = TypeBuilder::Profiler::CPUProfileNode::create()
-        .setFunctionName(toCoreString(node->GetFunctionName()))
-        .setScriptId(String::number(node->GetScriptId()))
-        .setUrl(toCoreString(node->GetScriptResourceName()))
-        .setLineNumber(node->GetLineNumber())
-        .setColumnNumber(node->GetColumnNumber())
-        .setHitCount(node->GetHitCount())
-        .setCallUID(node->GetCallUid())
-        .setChildren(children.release())
-        .setPositionTicks(positionTicks.release())
-        .setDeoptReason(node->GetBailoutReason())
-        .setId(node->GetNodeId());
-    return result.release();
-}
-
-PassRefPtr<TypeBuilder::Array<int>> buildInspectorObjectForSamples(v8::CpuProfile* v8profile)
-{
-    RefPtr<TypeBuilder::Array<int>> array = TypeBuilder::Array<int>::create();
-    int count = v8profile->GetSamplesCount();
-    for (int i = 0; i < count; i++)
-        array->addItem(v8profile->GetSample(i)->GetNodeId());
-    return array.release();
-}
-
-PassRefPtr<TypeBuilder::Array<double>> buildInspectorObjectForTimestamps(v8::CpuProfile* v8profile)
-{
-    RefPtr<TypeBuilder::Array<double>> array = TypeBuilder::Array<double>::create();
-    int count = v8profile->GetSamplesCount();
-    for (int i = 0; i < count; i++)
-        array->addItem(v8profile->GetSampleTimestamp(i));
-    return array.release();
-}
-
-PassRefPtr<TypeBuilder::Profiler::CPUProfile> createCPUProfile(v8::CpuProfile* v8profile)
-{
-    RefPtr<TypeBuilder::Profiler::CPUProfile> profile = TypeBuilder::Profiler::CPUProfile::create()
-        .setHead(buildInspectorObjectFor(v8profile->GetTopDownRoot()))
-        .setStartTime(static_cast<double>(v8profile->GetStartTime()) / 1000000)
-        .setEndTime(static_cast<double>(v8profile->GetEndTime()) / 1000000);
-    profile->setSamples(buildInspectorObjectForSamples(v8profile));
-    profile->setTimestamps(buildInspectorObjectForTimestamps(v8profile));
-    return profile.release();
-}
-
-PassRefPtr<TypeBuilder::Debugger::Location> currentDebugLocation()
-{
-    RefPtrWillBeRawPtr<ScriptCallStack> callStack(currentScriptCallStack(1));
-    const ScriptCallFrame& lastCaller = callStack->at(0);
-    RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
-        .setScriptId(lastCaller.scriptId())
-        .setLineNumber(lastCaller.lineNumber());
-    location->setColumnNumber(lastCaller.columnNumber());
-    return location.release();
-}
-
-} // namespace
-
-class InspectorProfilerAgent::ProfileDescriptor {
-public:
-    ProfileDescriptor(const String& id, const String& title)
-        : m_id(id)
-        , m_title(title) { }
-    String m_id;
-    String m_title;
-};
-
-PassOwnPtrWillBeRawPtr<InspectorProfilerAgent> InspectorProfilerAgent::create(v8::Isolate* isolate, InjectedScriptManager* injectedScriptManager, Client* client)
-{
-    return adoptPtrWillBeNoop(new InspectorProfilerAgent(isolate, injectedScriptManager, client));
-}
-
-InspectorProfilerAgent::InspectorProfilerAgent(v8::Isolate* isolate, InjectedScriptManager* injectedScriptManager, Client* client)
+InspectorProfilerAgent::InspectorProfilerAgent(v8::Isolate* isolate, Client* client)
     : InspectorBaseAgent<InspectorProfilerAgent, InspectorFrontend::Profiler>("Profiler")
-    , m_isolate(isolate)
-    , m_injectedScriptManager(injectedScriptManager)
-    , m_recordingCPUProfile(false)
     , m_client(client)
+    , m_v8ProfilerAgent(V8ProfilerAgent::create(isolate))
 {
 }
 
@@ -168,204 +60,100 @@
 {
 }
 
-void InspectorProfilerAgent::consoleProfile(ExecutionContext* context, const String& title)
+// InspectorBaseAgent overrides.
+void InspectorProfilerAgent::init()
 {
-    UseCounter::count(context, UseCounter::DevToolsConsoleProfile);
-    ASSERT(frontend() && enabled());
-    String id = nextProfileId();
-    m_startedProfiles.append(ProfileDescriptor(id, title));
-    startProfiling(id);
-    frontend()->consoleProfileStarted(id, currentDebugLocation(), title.isNull() ? 0 : &title);
+    m_v8ProfilerAgent->setInspectorState(m_state);
 }
 
-void InspectorProfilerAgent::consoleProfileEnd(const String& title)
+void InspectorProfilerAgent::setFrontend(InspectorFrontend* frontend)
 {
-    ASSERT(frontend() && enabled());
-    String id;
-    String resolvedTitle;
-    // Take last started profile if no title was passed.
-    if (title.isNull()) {
-        if (m_startedProfiles.isEmpty())
-            return;
-        id = m_startedProfiles.last().m_id;
-        resolvedTitle = m_startedProfiles.last().m_title;
-        m_startedProfiles.removeLast();
-    } else {
-        for (size_t i = 0; i < m_startedProfiles.size(); i++) {
-            if (m_startedProfiles[i].m_title == title) {
-                resolvedTitle = title;
-                id = m_startedProfiles[i].m_id;
-                m_startedProfiles.remove(i);
-                break;
-            }
-        }
-        if (id.isEmpty())
-            return;
-    }
-    RefPtr<TypeBuilder::Profiler::CPUProfile> profile = stopProfiling(id, true);
-    if (!profile)
-        return;
-    RefPtr<TypeBuilder::Debugger::Location> location = currentDebugLocation();
-    frontend()->consoleProfileFinished(id, location, profile, resolvedTitle.isNull() ? 0 : &resolvedTitle);
+    InspectorBaseAgent::setFrontend(frontend);
+    m_v8ProfilerAgent->setFrontend(InspectorFrontend::Profiler::from(frontend));
 }
 
-void InspectorProfilerAgent::enable(ErrorString*)
+void InspectorProfilerAgent::clearFrontend()
 {
-    m_state->setBoolean(ProfilerAgentState::profilerEnabled, true);
-    doEnable();
-}
-
-void InspectorProfilerAgent::doEnable()
-{
-    m_instrumentingAgents->setInspectorProfilerAgent(this);
-}
-
-void InspectorProfilerAgent::disable(ErrorString*)
-{
-    for (Vector<ProfileDescriptor>::reverse_iterator it = m_startedProfiles.rbegin(); it != m_startedProfiles.rend(); ++it)
-        stopProfiling(it->m_id, false);
-    m_startedProfiles.clear();
-    stop(0, 0);
-    m_instrumentingAgents->setInspectorProfilerAgent(nullptr);
-    m_state->setBoolean(ProfilerAgentState::profilerEnabled, false);
-}
-
-bool InspectorProfilerAgent::enabled()
-{
-    return m_state->getBoolean(ProfilerAgentState::profilerEnabled);
-}
-
-void InspectorProfilerAgent::setSamplingInterval(ErrorString* error, int interval)
-{
-    if (m_recordingCPUProfile) {
-        *error = "Cannot change sampling interval when profiling.";
-        return;
-    }
-    m_state->setLong(ProfilerAgentState::samplingInterval, interval);
-    m_isolate->GetCpuProfiler()->SetSamplingInterval(interval);
+    m_v8ProfilerAgent->clearFrontend();
+    InspectorBaseAgent::clearFrontend();
 }
 
 void InspectorProfilerAgent::restore()
 {
-    if (m_state->getBoolean(ProfilerAgentState::profilerEnabled))
-        doEnable();
-    if (long interval = m_state->getLong(ProfilerAgentState::samplingInterval, 0))
-        m_isolate->GetCpuProfiler()->SetSamplingInterval(interval);
-    if (m_state->getBoolean(ProfilerAgentState::userInitiatedProfiling)) {
-        ErrorString error;
-        start(&error);
-    }
+    if (!m_state->getBoolean(ProfilerAgentState::profilerEnabled))
+        return;
+    m_v8ProfilerAgent->restore();
+    ErrorString errorString;
+    enable(&errorString);
+}
+
+// Protocol implementation.
+void InspectorProfilerAgent::consoleProfile(ExecutionContext* context, const String& title)
+{
+    UseCounter::count(context, UseCounter::DevToolsConsoleProfile);
+    m_v8ProfilerAgent->consoleProfile(title);
+}
+
+void InspectorProfilerAgent::consoleProfileEnd(const String& title)
+{
+    m_v8ProfilerAgent->consoleProfileEnd(title);
+}
+
+void InspectorProfilerAgent::enable(ErrorString* errorString)
+{
+    m_v8ProfilerAgent->enable(errorString);
+    m_state->setBoolean(ProfilerAgentState::profilerEnabled, true);
+    m_instrumentingAgents->setInspectorProfilerAgent(this);
+}
+
+void InspectorProfilerAgent::disable(ErrorString* errorString)
+{
+    m_instrumentingAgents->setInspectorProfilerAgent(nullptr);
+    m_state->setBoolean(ProfilerAgentState::profilerEnabled, false);
+    m_v8ProfilerAgent->disable(errorString);
+}
+
+void InspectorProfilerAgent::setSamplingInterval(ErrorString* error, int interval)
+{
+    m_v8ProfilerAgent->setSamplingInterval(error, interval);
 }
 
 void InspectorProfilerAgent::start(ErrorString* error)
 {
-    if (m_recordingCPUProfile)
-        return;
-    if (!enabled()) {
-        *error = "Profiler is not enabled";
-        return;
-    }
-    m_recordingCPUProfile = true;
-    if (m_client)
+    m_v8ProfilerAgent->start(error);
+    if (m_client && !*error)
         m_client->profilingStarted();
-    m_frontendInitiatedProfileId = nextProfileId();
-    startProfiling(m_frontendInitiatedProfileId);
-    m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, true);
 }
 
 void InspectorProfilerAgent::stop(ErrorString* errorString, RefPtr<TypeBuilder::Profiler::CPUProfile>& profile)
 {
-    stop(errorString, &profile);
-}
-
-void InspectorProfilerAgent::stop(ErrorString* errorString, RefPtr<TypeBuilder::Profiler::CPUProfile>* profile)
-{
-    if (!m_recordingCPUProfile) {
-        if (errorString)
-            *errorString = "No recording profiles found";
-        return;
-    }
-    m_recordingCPUProfile = false;
     if (m_client)
         m_client->profilingStopped();
-    RefPtr<TypeBuilder::Profiler::CPUProfile> cpuProfile = stopProfiling(m_frontendInitiatedProfileId, !!profile);
-    if (profile) {
-        *profile = cpuProfile;
-        if (!cpuProfile && errorString)
-            *errorString = "Profile wasn't found";
-    }
-    m_frontendInitiatedProfileId = String();
-    m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, false);
-}
-
-String InspectorProfilerAgent::nextProfileId()
-{
-    long nextId = m_state->getLong(ProfilerAgentState::nextProfileId, 1);
-    m_state->setLong(ProfilerAgentState::nextProfileId, nextId + 1);
-    return String::number(nextId);
-}
-
-void InspectorProfilerAgent::startProfiling(const String& title)
-{
-    v8::HandleScope handleScope(m_isolate);
-    m_isolate->GetCpuProfiler()->StartProfiling(v8String(m_isolate, title), true);
-}
-
-PassRefPtr<TypeBuilder::Profiler::CPUProfile> InspectorProfilerAgent::stopProfiling(const String& title, bool serialize)
-{
-    v8::HandleScope handleScope(m_isolate);
-    v8::CpuProfile* profile = m_isolate->GetCpuProfiler()->StopProfiling(v8String(m_isolate, title));
-    if (!profile)
-        return nullptr;
-    RefPtr<TypeBuilder::Profiler::CPUProfile> result;
-    if (serialize)
-        result = createCPUProfile(profile);
-    profile->Delete();
-    return result.release();
-}
-
-bool InspectorProfilerAgent::isRecording() const
-{
-    return m_recordingCPUProfile || !m_startedProfiles.isEmpty();
-}
-
-void InspectorProfilerAgent::idleFinished()
-{
-    if (!isRecording())
-        return;
-    m_isolate->GetCpuProfiler()->SetIdle(false);
-}
-
-void InspectorProfilerAgent::idleStarted()
-{
-    if (!isRecording())
-        return;
-    m_isolate->GetCpuProfiler()->SetIdle(true);
+    m_v8ProfilerAgent->stop(errorString, profile);
 }
 
 void InspectorProfilerAgent::willProcessTask()
 {
-    idleFinished();
+    m_v8ProfilerAgent->idleFinished();
 }
 
 void InspectorProfilerAgent::didProcessTask()
 {
-    idleStarted();
+    m_v8ProfilerAgent->idleStarted();
 }
 
 void InspectorProfilerAgent::willEnterNestedRunLoop()
 {
-    idleStarted();
+    m_v8ProfilerAgent->idleStarted();
 }
 
 void InspectorProfilerAgent::didLeaveNestedRunLoop()
 {
-    idleFinished();
+    m_v8ProfilerAgent->idleFinished();
 }
 
 DEFINE_TRACE(InspectorProfilerAgent)
 {
-    visitor->trace(m_injectedScriptManager);
     InspectorBaseAgent::trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.h b/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.h
index 61640db7..2da64d3 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.h
@@ -34,20 +34,15 @@
 #include "core/InspectorFrontend.h"
 #include "core/inspector/InspectorBaseAgent.h"
 #include "wtf/Forward.h"
-#include "wtf/HashMap.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/text/WTFString.h"
 
-namespace v8 {
-class CpuProfile;
-}
-
 namespace blink {
 
 class ExecutionContext;
-class InjectedScriptManager;
 class InspectorFrontend;
+class V8ProfilerAgent;
 
 typedef String ErrorString;
 
@@ -62,47 +57,35 @@
         virtual void profilingStopped() { }
     };
 
-    static PassOwnPtrWillBeRawPtr<InspectorProfilerAgent> create(v8::Isolate*, InjectedScriptManager*, Client*);
+    static PassOwnPtrWillBeRawPtr<InspectorProfilerAgent> create(v8::Isolate*, Client*);
     ~InspectorProfilerAgent() override;
     DECLARE_VIRTUAL_TRACE();
 
+    // InspectorBaseAgent overrides.
+    void init() override;
+    void setFrontend(InspectorFrontend*) override;
+    void clearFrontend() override;
+    void restore() override;
+
     void consoleProfile(ExecutionContext*, const String& title);
     void consoleProfileEnd(const String& title);
 
     void enable(ErrorString*) override;
+    void disable(ErrorString*) override;
     void setSamplingInterval(ErrorString*, int) override;
     void start(ErrorString*) override;
     void stop(ErrorString*, RefPtr<TypeBuilder::Profiler::CPUProfile>&) override;
 
-    void disable(ErrorString*) override;
-    void restore() override;
-
     void willProcessTask();
     void didProcessTask();
     void willEnterNestedRunLoop();
     void didLeaveNestedRunLoop();
 
 private:
-    InspectorProfilerAgent(v8::Isolate*, InjectedScriptManager*, Client*);
-    bool enabled();
-    void doEnable();
-    void stop(ErrorString*, RefPtr<TypeBuilder::Profiler::CPUProfile>*);
-    String nextProfileId();
+    InspectorProfilerAgent(v8::Isolate*, Client*);
 
-    void startProfiling(const String& title);
-    PassRefPtr<TypeBuilder::Profiler::CPUProfile> stopProfiling(const String& title, bool serialize);
-
-    bool isRecording() const;
-    void idleStarted();
-    void idleFinished();
-
-    v8::Isolate* m_isolate;
-    RawPtrWillBeMember<InjectedScriptManager> m_injectedScriptManager;
-    bool m_recordingCPUProfile;
-    class ProfileDescriptor;
-    Vector<ProfileDescriptor> m_startedProfiles;
-    String m_frontendInitiatedProfileId;
     Client* m_client;
+    OwnPtr<V8ProfilerAgent> m_v8ProfilerAgent;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp b/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp
index f6c31aa..31822ea 100644
--- a/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp
+++ b/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp
@@ -136,7 +136,7 @@
     m_agents.append(workerDebuggerAgent.release());
 
     v8::Isolate* isolate = workerGlobalScope->thread()->isolate();
-    m_agents.append(InspectorProfilerAgent::create(isolate, m_injectedScriptManager.get(), 0));
+    m_agents.append(InspectorProfilerAgent::create(isolate, 0));
     m_agents.append(InspectorHeapProfilerAgent::create(isolate, m_injectedScriptManager.get()));
 
     OwnPtrWillBeRawPtr<WorkerConsoleAgent> workerConsoleAgent = WorkerConsoleAgent::create(m_injectedScriptManager.get(), workerGlobalScope);
diff --git a/third_party/WebKit/Source/core/inspector/v8/V8ProfilerAgent.h b/third_party/WebKit/Source/core/inspector/v8/V8ProfilerAgent.h
new file mode 100644
index 0000000..6e375f9
--- /dev/null
+++ b/third_party/WebKit/Source/core/inspector/v8/V8ProfilerAgent.h
@@ -0,0 +1,53 @@
+// 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 V8ProfilerAgent_h
+#define V8ProfilerAgent_h
+
+#include "core/CoreExport.h"
+#include "core/InspectorFrontend.h"
+#include "wtf/Forward.h"
+#include "wtf/Noncopyable.h"
+#include "wtf/text/WTFString.h"
+
+namespace v8 {
+class Isolate;
+}
+
+namespace blink {
+
+class InspectorState;
+
+typedef String ErrorString;
+
+class CORE_EXPORT V8ProfilerAgent {
+public:
+    static PassOwnPtr<V8ProfilerAgent> create(v8::Isolate*);
+    virtual ~V8ProfilerAgent() { }
+
+    // State management methods.
+    virtual void setInspectorState(InspectorState*) = 0;
+    virtual void setFrontend(InspectorFrontend::Profiler*) = 0;
+    virtual void clearFrontend() = 0;
+    virtual void restore() = 0;
+
+    // Protocol methods.
+    virtual void enable(ErrorString*) = 0;
+    virtual void disable(ErrorString*) = 0;
+    virtual void setSamplingInterval(ErrorString*, int) = 0;
+    virtual void start(ErrorString*) = 0;
+    virtual void stop(ErrorString*, RefPtr<TypeBuilder::Profiler::CPUProfile>&) = 0;
+
+    // API for the embedder.
+    virtual void consoleProfile(const String& title) = 0;
+    virtual void consoleProfileEnd(const String& title) = 0;
+
+    virtual void idleStarted() = 0;
+    virtual void idleFinished() = 0;
+};
+
+} // namespace blink
+
+
+#endif // !defined(V8ProfilerAgent_h)
diff --git a/third_party/WebKit/Source/core/inspector/v8/V8ProfilerAgentImpl.cpp b/third_party/WebKit/Source/core/inspector/v8/V8ProfilerAgentImpl.cpp
new file mode 100644
index 0000000..bf9afa9f
--- /dev/null
+++ b/third_party/WebKit/Source/core/inspector/v8/V8ProfilerAgentImpl.cpp
@@ -0,0 +1,306 @@
+// 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 "config.h"
+#include "core/inspector/v8/V8ProfilerAgentImpl.h"
+
+#include "bindings/core/v8/ScriptCallStackFactory.h"
+#include "bindings/core/v8/V8Binding.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/ScriptCallStack.h"
+#include <v8-profiler.h>
+
+namespace blink {
+
+namespace ProfilerAgentState {
+static const char samplingInterval[] = "samplingInterval";
+static const char userInitiatedProfiling[] = "userInitiatedProfiling";
+static const char nextProfileId[] = "nextProfileId";
+}
+
+namespace {
+
+PassRefPtr<TypeBuilder::Array<TypeBuilder::Profiler::PositionTickInfo>> buildInspectorObjectForPositionTicks(const v8::CpuProfileNode* node)
+{
+    RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::PositionTickInfo>> array = TypeBuilder::Array<TypeBuilder::Profiler::PositionTickInfo>::create();
+    unsigned lineCount = node->GetHitLineCount();
+    if (!lineCount)
+        return array.release();
+
+    Vector<v8::CpuProfileNode::LineTick> entries(lineCount);
+    if (node->GetLineTicks(&entries[0], lineCount)) {
+        for (unsigned i = 0; i < lineCount; i++) {
+            RefPtr<TypeBuilder::Profiler::PositionTickInfo> line = TypeBuilder::Profiler::PositionTickInfo::create()
+                .setLine(entries[i].line)
+                .setTicks(entries[i].hit_count);
+            array->addItem(line);
+        }
+    }
+
+    return array.release();
+}
+
+PassRefPtr<TypeBuilder::Profiler::CPUProfileNode> buildInspectorObjectFor(const v8::CpuProfileNode* node)
+{
+    v8::HandleScope handleScope(v8::Isolate::GetCurrent());
+
+    RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>> children = TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>::create();
+    const int childrenCount = node->GetChildrenCount();
+    for (int i = 0; i < childrenCount; i++) {
+        const v8::CpuProfileNode* child = node->GetChild(i);
+        children->addItem(buildInspectorObjectFor(child));
+    }
+
+    RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::PositionTickInfo>> positionTicks = buildInspectorObjectForPositionTicks(node);
+
+    RefPtr<TypeBuilder::Profiler::CPUProfileNode> result = TypeBuilder::Profiler::CPUProfileNode::create()
+        .setFunctionName(toCoreString(node->GetFunctionName()))
+        .setScriptId(String::number(node->GetScriptId()))
+        .setUrl(toCoreString(node->GetScriptResourceName()))
+        .setLineNumber(node->GetLineNumber())
+        .setColumnNumber(node->GetColumnNumber())
+        .setHitCount(node->GetHitCount())
+        .setCallUID(node->GetCallUid())
+        .setChildren(children.release())
+        .setPositionTicks(positionTicks.release())
+        .setDeoptReason(node->GetBailoutReason())
+        .setId(node->GetNodeId());
+    return result.release();
+}
+
+PassRefPtr<TypeBuilder::Array<int>> buildInspectorObjectForSamples(v8::CpuProfile* v8profile)
+{
+    RefPtr<TypeBuilder::Array<int>> array = TypeBuilder::Array<int>::create();
+    int count = v8profile->GetSamplesCount();
+    for (int i = 0; i < count; i++)
+        array->addItem(v8profile->GetSample(i)->GetNodeId());
+    return array.release();
+}
+
+PassRefPtr<TypeBuilder::Array<double>> buildInspectorObjectForTimestamps(v8::CpuProfile* v8profile)
+{
+    RefPtr<TypeBuilder::Array<double>> array = TypeBuilder::Array<double>::create();
+    int count = v8profile->GetSamplesCount();
+    for (int i = 0; i < count; i++)
+        array->addItem(v8profile->GetSampleTimestamp(i));
+    return array.release();
+}
+
+PassRefPtr<TypeBuilder::Profiler::CPUProfile> createCPUProfile(v8::CpuProfile* v8profile)
+{
+    RefPtr<TypeBuilder::Profiler::CPUProfile> profile = TypeBuilder::Profiler::CPUProfile::create()
+        .setHead(buildInspectorObjectFor(v8profile->GetTopDownRoot()))
+        .setStartTime(static_cast<double>(v8profile->GetStartTime()) / 1000000)
+        .setEndTime(static_cast<double>(v8profile->GetEndTime()) / 1000000);
+    profile->setSamples(buildInspectorObjectForSamples(v8profile));
+    profile->setTimestamps(buildInspectorObjectForTimestamps(v8profile));
+    return profile.release();
+}
+
+PassRefPtr<TypeBuilder::Debugger::Location> currentDebugLocation()
+{
+    RefPtrWillBeRawPtr<ScriptCallStack> callStack(currentScriptCallStack(1));
+    const ScriptCallFrame& lastCaller = callStack->at(0);
+    RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
+        .setScriptId(lastCaller.scriptId())
+        .setLineNumber(lastCaller.lineNumber());
+    location->setColumnNumber(lastCaller.columnNumber());
+    return location.release();
+}
+
+} // namespace
+
+class V8ProfilerAgentImpl::ProfileDescriptor {
+public:
+    ProfileDescriptor(const String& id, const String& title)
+        : m_id(id)
+        , m_title(title) { }
+    String m_id;
+    String m_title;
+};
+
+PassOwnPtr<V8ProfilerAgent> V8ProfilerAgent::create(v8::Isolate* isolate)
+{
+    return adoptPtr(new V8ProfilerAgentImpl(isolate));
+}
+
+V8ProfilerAgentImpl::V8ProfilerAgentImpl(v8::Isolate* isolate)
+    : m_isolate(isolate)
+    , m_state(nullptr)
+    , m_frontend(nullptr)
+    , m_enabled(false)
+    , m_recordingCPUProfile(false)
+{
+}
+
+V8ProfilerAgentImpl::~V8ProfilerAgentImpl()
+{
+}
+
+void V8ProfilerAgentImpl::consoleProfile(const String& title)
+{
+    ASSERT(m_frontend && m_enabled);
+    String id = nextProfileId();
+    m_startedProfiles.append(ProfileDescriptor(id, title));
+    startProfiling(id);
+    m_frontend->consoleProfileStarted(id, currentDebugLocation(), title.isNull() ? 0 : &title);
+}
+
+void V8ProfilerAgentImpl::consoleProfileEnd(const String& title)
+{
+    ASSERT(m_frontend && m_enabled);
+    String id;
+    String resolvedTitle;
+    // Take last started profile if no title was passed.
+    if (title.isNull()) {
+        if (m_startedProfiles.isEmpty())
+            return;
+        id = m_startedProfiles.last().m_id;
+        resolvedTitle = m_startedProfiles.last().m_title;
+        m_startedProfiles.removeLast();
+    } else {
+        for (size_t i = 0; i < m_startedProfiles.size(); i++) {
+            if (m_startedProfiles[i].m_title == title) {
+                resolvedTitle = title;
+                id = m_startedProfiles[i].m_id;
+                m_startedProfiles.remove(i);
+                break;
+            }
+        }
+        if (id.isEmpty())
+            return;
+    }
+    RefPtr<TypeBuilder::Profiler::CPUProfile> profile = stopProfiling(id, true);
+    if (!profile)
+        return;
+    RefPtr<TypeBuilder::Debugger::Location> location = currentDebugLocation();
+    m_frontend->consoleProfileFinished(id, location, profile, resolvedTitle.isNull() ? 0 : &resolvedTitle);
+}
+
+void V8ProfilerAgentImpl::enable(ErrorString*)
+{
+    m_enabled = true;
+}
+
+void V8ProfilerAgentImpl::disable(ErrorString*)
+{
+    for (Vector<ProfileDescriptor>::reverse_iterator it = m_startedProfiles.rbegin(); it != m_startedProfiles.rend(); ++it)
+        stopProfiling(it->m_id, false);
+    m_startedProfiles.clear();
+    stop(0, 0);
+    m_enabled = false;
+}
+
+void V8ProfilerAgentImpl::setSamplingInterval(ErrorString* error, int interval)
+{
+    if (m_recordingCPUProfile) {
+        *error = "Cannot change sampling interval when profiling.";
+        return;
+    }
+    m_state->setLong(ProfilerAgentState::samplingInterval, interval);
+    m_isolate->GetCpuProfiler()->SetSamplingInterval(interval);
+}
+
+void V8ProfilerAgentImpl::clearFrontend()
+{
+    ErrorString error;
+    disable(&error);
+    ASSERT(m_frontend);
+    m_frontend = nullptr;
+}
+
+void V8ProfilerAgentImpl::restore()
+{
+    m_enabled = true;
+    if (long interval = m_state->getLong(ProfilerAgentState::samplingInterval, 0))
+        m_isolate->GetCpuProfiler()->SetSamplingInterval(interval);
+    if (m_state->getBoolean(ProfilerAgentState::userInitiatedProfiling)) {
+        ErrorString error;
+        start(&error);
+    }
+}
+
+void V8ProfilerAgentImpl::start(ErrorString* error)
+{
+    if (m_recordingCPUProfile)
+        return;
+    if (!m_enabled) {
+        *error = "Profiler is not enabled";
+        return;
+    }
+    m_recordingCPUProfile = true;
+    m_frontendInitiatedProfileId = nextProfileId();
+    startProfiling(m_frontendInitiatedProfileId);
+    m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, true);
+}
+
+void V8ProfilerAgentImpl::stop(ErrorString* errorString, RefPtr<TypeBuilder::Profiler::CPUProfile>& profile)
+{
+    stop(errorString, &profile);
+}
+
+void V8ProfilerAgentImpl::stop(ErrorString* errorString, RefPtr<TypeBuilder::Profiler::CPUProfile>* profile)
+{
+    if (!m_recordingCPUProfile) {
+        if (errorString)
+            *errorString = "No recording profiles found";
+        return;
+    }
+    m_recordingCPUProfile = false;
+    RefPtr<TypeBuilder::Profiler::CPUProfile> cpuProfile = stopProfiling(m_frontendInitiatedProfileId, !!profile);
+    if (profile) {
+        *profile = cpuProfile;
+        if (!cpuProfile && errorString)
+            *errorString = "Profile wasn't found";
+    }
+    m_frontendInitiatedProfileId = String();
+    m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, false);
+}
+
+String V8ProfilerAgentImpl::nextProfileId()
+{
+    long nextId = m_state->getLong(ProfilerAgentState::nextProfileId, 1);
+    m_state->setLong(ProfilerAgentState::nextProfileId, nextId + 1);
+    return String::number(nextId);
+}
+
+void V8ProfilerAgentImpl::startProfiling(const String& title)
+{
+    v8::HandleScope handleScope(m_isolate);
+    m_isolate->GetCpuProfiler()->StartProfiling(v8String(m_isolate, title), true);
+}
+
+PassRefPtr<TypeBuilder::Profiler::CPUProfile> V8ProfilerAgentImpl::stopProfiling(const String& title, bool serialize)
+{
+    v8::HandleScope handleScope(m_isolate);
+    v8::CpuProfile* profile = m_isolate->GetCpuProfiler()->StopProfiling(v8String(m_isolate, title));
+    if (!profile)
+        return nullptr;
+    RefPtr<TypeBuilder::Profiler::CPUProfile> result;
+    if (serialize)
+        result = createCPUProfile(profile);
+    profile->Delete();
+    return result.release();
+}
+
+bool V8ProfilerAgentImpl::isRecording() const
+{
+    return m_recordingCPUProfile || !m_startedProfiles.isEmpty();
+}
+
+void V8ProfilerAgentImpl::idleFinished()
+{
+    if (!isRecording())
+        return;
+    m_isolate->GetCpuProfiler()->SetIdle(false);
+}
+
+void V8ProfilerAgentImpl::idleStarted()
+{
+    if (!isRecording())
+        return;
+    m_isolate->GetCpuProfiler()->SetIdle(true);
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/v8/V8ProfilerAgentImpl.h b/third_party/WebKit/Source/core/inspector/v8/V8ProfilerAgentImpl.h
new file mode 100644
index 0000000..7ba14e0
--- /dev/null
+++ b/third_party/WebKit/Source/core/inspector/v8/V8ProfilerAgentImpl.h
@@ -0,0 +1,62 @@
+// 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 V8ProfilerAgentImpl_h
+#define V8ProfilerAgentImpl_h
+
+#include "core/CoreExport.h"
+#include "core/InspectorFrontend.h"
+#include "core/inspector/v8/V8ProfilerAgent.h"
+#include "wtf/Forward.h"
+#include "wtf/Noncopyable.h"
+#include "wtf/text/WTFString.h"
+
+namespace blink {
+
+class CORE_EXPORT V8ProfilerAgentImpl : public V8ProfilerAgent {
+    WTF_MAKE_NONCOPYABLE(V8ProfilerAgentImpl);
+public:
+    explicit V8ProfilerAgentImpl(v8::Isolate*);
+    ~V8ProfilerAgentImpl() override;
+
+    void setInspectorState(InspectorState* state) override { m_state = state; }
+    void setFrontend(InspectorFrontend::Profiler* frontend) override { m_frontend = frontend; }
+    void clearFrontend() override;
+    void restore() override;
+
+    void enable(ErrorString*) override;
+    void disable(ErrorString*) override;
+    void setSamplingInterval(ErrorString*, int) override;
+    void start(ErrorString*) override;
+    void stop(ErrorString*, RefPtr<TypeBuilder::Profiler::CPUProfile>&) override;
+
+    void consoleProfile(const String& title) override;
+    void consoleProfileEnd(const String& title) override;
+
+    void idleStarted();
+    void idleFinished();
+
+private:
+    void stop(ErrorString*, RefPtr<TypeBuilder::Profiler::CPUProfile>*);
+    String nextProfileId();
+
+    void startProfiling(const String& title);
+    PassRefPtr<TypeBuilder::Profiler::CPUProfile> stopProfiling(const String& title, bool serialize);
+
+    bool isRecording() const;
+
+    v8::Isolate* m_isolate;
+    InspectorState* m_state;
+    InspectorFrontend::Profiler* m_frontend;
+    bool m_enabled;
+    bool m_recordingCPUProfile;
+    class ProfileDescriptor;
+    Vector<ProfileDescriptor> m_startedProfiles;
+    String m_frontendInitiatedProfileId;
+};
+
+} // namespace blink
+
+
+#endif // !defined(V8ProfilerAgentImpl_h)
diff --git a/third_party/WebKit/Source/core/layout/ImageQualityControllerTest.cpp b/third_party/WebKit/Source/core/layout/ImageQualityControllerTest.cpp
index 41fcfd9..bd1fbe0 100644
--- a/third_party/WebKit/Source/core/layout/ImageQualityControllerTest.cpp
+++ b/third_party/WebKit/Source/core/layout/ImageQualityControllerTest.cpp
@@ -107,7 +107,7 @@
 
     RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality);
     OwnPtr<PaintController> paintController = PaintController::create();
-    GraphicsContext context(paintController.get());
+    GraphicsContext context(*paintController);
     EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(&context, img, testImage.get(), testImage.get(), LayoutSize(1, 1)));
 }
 
@@ -135,7 +135,7 @@
 
     RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality);
     OwnPtr<PaintController> paintController = PaintController::create();
-    GraphicsContext context(paintController.get());
+    GraphicsContext context(*paintController);
 
     // Start a resize
     document().frame()->view()->willStartLiveResize();
@@ -167,7 +167,7 @@
 
     RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality);
     OwnPtr<PaintController> paintController = PaintController::create();
-    GraphicsContext context(paintController.get());
+    GraphicsContext context(*paintController);
 
     // Paint once. This will kick off a timer to see if we resize it during that timer's execution.
     EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(&context, img, testImage.get(), testImage.get(), LayoutSize(2, 2)));
@@ -192,7 +192,7 @@
 
     RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality);
     OwnPtr<PaintController> paintController = PaintController::create();
-    GraphicsContext context(paintController.get());
+    GraphicsContext context(*paintController);
 
     // Paint once. This will kick off a timer to see if we resize it during that timer's execution.
     EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(&context, img, testImage.get(), testImage.get(), LayoutSize(2, 2)));
diff --git a/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp b/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
index 53a2b872..329b4205 100644
--- a/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
@@ -125,6 +125,7 @@
         return false;
 
     LayoutRect paintRect(visualOverflowRect());
+    paintRect.unite(localSelectionRect());
     paintRect.moveBy(paintOffset + location());
 
     // Early exit if the element touches the edges.
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h
index 1048eae..6414307 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.h
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -148,7 +148,7 @@
 
     void openFileChooser(LocalFrame*, PassRefPtr<FileChooser>) override;
 
-    void setCursor(const Cursor&) override {}
+    void setCursor(const Cursor&, LocalFrame* localRoot) override {}
     Cursor lastSetCursorForTesting() const override { return pointerCursor(); }
 
     void attachRootGraphicsLayer(GraphicsLayer*, LocalFrame* localRoot) override {}
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h
index 9146f69..b474502 100644
--- a/third_party/WebKit/Source/core/page/ChromeClient.h
+++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -140,7 +140,7 @@
 
     // Methods used by HostWindow.
     virtual WebScreenInfo screenInfo() const = 0;
-    virtual void setCursor(const Cursor&) = 0;
+    virtual void setCursor(const Cursor&, LocalFrame* localRoot) = 0;
     // End methods used by HostWindow.
     virtual Cursor lastSetCursorForTesting() const = 0;
 
diff --git a/third_party/WebKit/Source/core/paint/LayerClipRecorderTest.cpp b/third_party/WebKit/Source/core/paint/LayerClipRecorderTest.cpp
index 25d92c4..5f07cd0 100644
--- a/third_party/WebKit/Source/core/paint/LayerClipRecorderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/LayerClipRecorderTest.cpp
@@ -60,7 +60,7 @@
 
 TEST_F(LayerClipRecorderTest, Single)
 {
-    GraphicsContext context(&rootPaintController());
+    GraphicsContext context(rootPaintController());
     LayoutRect bound = layoutView().viewRect();
     EXPECT_EQ((size_t)0, rootPaintController().displayItemList().size());
 
@@ -74,7 +74,7 @@
 
 TEST_F(LayerClipRecorderTest, Empty)
 {
-    GraphicsContext context(&rootPaintController());
+    GraphicsContext context(rootPaintController());
     EXPECT_EQ((size_t)0, rootPaintController().displayItemList().size());
 
     drawEmptyClip(context, layoutView(), PaintPhaseForeground);
diff --git a/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorderTest.cpp b/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorderTest.cpp
index 077919f..9f41d0ff 100644
--- a/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorderTest.cpp
@@ -41,7 +41,7 @@
 
 TEST_F(LayoutObjectDrawingRecorderTest, Nothing)
 {
-    GraphicsContext context(&rootPaintController());
+    GraphicsContext context(rootPaintController());
     LayoutRect bound = layoutView().viewRect();
     EXPECT_EQ((size_t)0, rootPaintController().displayItemList().size());
 
@@ -54,7 +54,7 @@
 
 TEST_F(LayoutObjectDrawingRecorderTest, Rect)
 {
-    GraphicsContext context(&rootPaintController());
+    GraphicsContext context(rootPaintController());
     LayoutRect bound = layoutView().viewRect();
     drawRect(context, layoutView(), PaintPhaseForeground, bound);
     rootPaintController().commitNewDisplayItems();
@@ -64,7 +64,7 @@
 
 TEST_F(LayoutObjectDrawingRecorderTest, Cached)
 {
-    GraphicsContext context(&rootPaintController());
+    GraphicsContext context(rootPaintController());
     LayoutRect bound = layoutView().viewRect();
     drawNothing(context, layoutView(), PaintPhaseBlockBackground, bound);
     drawRect(context, layoutView(), PaintPhaseForeground, bound);
@@ -94,7 +94,7 @@
     controller.invalidateAll();
     {
         // Draw some things which will produce a non-null picture.
-        GraphicsContext context(&controller);
+        GraphicsContext context(controller);
         LayoutObjectDrawingRecorder recorder(
             context, layoutObject, DisplayItem::BoxDecorationBackground, bounds, LayoutPoint());
         context.drawRect(enclosedIntRect(FloatRect(bounds)));
@@ -123,7 +123,7 @@
 {
     RuntimeEnabledFeatures::setSlimmingPaintOffsetCachingEnabled(true);
 
-    GraphicsContext context(&rootPaintController());
+    GraphicsContext context(rootPaintController());
     LayoutRect bounds = layoutView().viewRect();
     LayoutPoint paintOffset(1, 2);
 
diff --git a/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.cpp b/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.cpp
index 9af8907..48187b1 100644
--- a/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.cpp
@@ -25,7 +25,7 @@
     LayoutObject& divLayoutObject = *document().body()->firstChild()->layoutObject();
     InlineTextBox& textInlineBox = *toLayoutText(div.firstChild()->layoutObject())->firstTextBox();
 
-    GraphicsContext context(&rootPaintController());
+    GraphicsContext context(rootPaintController());
     PaintLayerPaintingInfo paintingInfo(&rootLayer, LayoutRect(0, 0, 800, 600), GlobalPaintNormalPhase, LayoutSize());
     PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases);
     rootPaintController().commitNewDisplayItems();
@@ -58,7 +58,7 @@
     InlineTextBox& firstTextBox = *text.firstTextBox();
     DisplayItemClient firstTextBoxDisplayItemClient = firstTextBox.displayItemClient();
 
-    GraphicsContext context(&rootPaintController());
+    GraphicsContext context(rootPaintController());
     PaintLayerPaintingInfo paintingInfo(&rootLayer, LayoutRect(0, 0, 800, 600), GlobalPaintNormalPhase, LayoutSize());
     PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases);
     rootPaintController().commitNewDisplayItems();
diff --git a/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h b/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h
index 7dd39bc9..43952c1 100644
--- a/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h
+++ b/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h
@@ -17,7 +17,7 @@
 class PaintControllerPaintTest : public RenderingTest {
 public:
     PaintControllerPaintTest()
-        : m_originalSlimmingPaintSubsequenceCachingEnabled(RuntimeEnabledFeatures::slimmingPaintSubsequenceCachingEnabled())
+        : m_originalSlimmingPaintSynchronizedPaintingEnabled(RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled())
         , m_originalSlimmingPaintOffsetCachingEnabled(RuntimeEnabledFeatures::slimmingPaintOffsetCachingEnabled())
         { }
 
@@ -30,14 +30,16 @@
     {
         RenderingTest::SetUp();
         enableCompositing();
+        GraphicsLayer::setDrawDebugRedFillForTesting(false);
     }
     void TearDown() override
     {
-        RuntimeEnabledFeatures::setSlimmingPaintSubsequenceCachingEnabled(m_originalSlimmingPaintSubsequenceCachingEnabled);
+        RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(m_originalSlimmingPaintSynchronizedPaintingEnabled);
         RuntimeEnabledFeatures::setSlimmingPaintOffsetCachingEnabled(m_originalSlimmingPaintOffsetCachingEnabled);
+        GraphicsLayer::setDrawDebugRedFillForTesting(true);
     }
 
-    bool m_originalSlimmingPaintSubsequenceCachingEnabled;
+    bool m_originalSlimmingPaintSynchronizedPaintingEnabled;
     bool m_originalSlimmingPaintOffsetCachingEnabled;
 };
 
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index 36bfa4d4..94ca11e 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -2716,6 +2716,13 @@
     }
 }
 
+void PaintLayer::clearNeedsRepaintRecursively()
+{
+    for (PaintLayer* child = firstChild(); child; child = child->nextSibling())
+        child->clearNeedsRepaintRecursively();
+    m_needsRepaint = false;
+}
+
 ObjectPaintProperties& PaintLayer::mutablePaintProperties()
 {
     ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h
index e825290..5be2384 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.h
@@ -598,7 +598,7 @@
 
     bool needsRepaint() const { return m_needsRepaint; }
     void setNeedsRepaint();
-    void clearNeedsRepaint() { m_needsRepaint = false; }
+    void clearNeedsRepaintRecursively();
 
     IntSize previousScrollOffsetAccumulationForPainting() const { return m_previousScrollOffsetAccumulationForPainting; }
     void setPreviousScrollOffsetAccumulationForPainting(const IntSize& s) { m_previousScrollOffsetAccumulationForPainting = s; }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
index 2069581..e9cb238 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -58,17 +58,6 @@
 
 PaintLayerPainter::PaintResult PaintLayerPainter::paintLayer(GraphicsContext* context, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
 {
-    PaintResult result = paintLayerInternal(context, paintingInfo, paintFlags);
-    // TODO(wangxianzhu): We may paint a layer multiple times with different flags.
-    // The following ensures the flag is only cleared once after the last painting.
-    // This is fragile but is temporary for spv1.
-    if ((paintFlags & PaintLayerPaintingCompositingForegroundPhase) || m_paintLayer.layoutObject()->isLayoutView())
-        m_paintLayer.clearNeedsRepaint();
-    return result;
-}
-
-PaintLayerPainter::PaintResult PaintLayerPainter::paintLayerInternal(GraphicsContext* context, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
-{
     // https://code.google.com/p/chromium/issues/detail?id=343772
     DisableCompositingQueryAsserts disabler;
 
@@ -122,7 +111,7 @@
     }
 
     localPaintFlags |= PaintLayerPaintingCompositingAllPhases;
-    if (paintLayerContentsInternal(context, paintingInfo, localPaintFlags, fragmentPolicy) == MaybeNotFullyPainted)
+    if (paintLayerContents(context, paintingInfo, localPaintFlags, fragmentPolicy) == MaybeNotFullyPainted)
         result = MaybeNotFullyPainted;
 
     return result;
@@ -190,18 +179,7 @@
     GraphicsContext* m_context;
 };
 
-PaintLayerPainter::PaintResult PaintLayerPainter::paintLayerContents(GraphicsContext* context, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, FragmentPolicy fragmentPolicy)
-{
-    PaintResult result = paintLayerContentsInternal(context, paintingInfo, paintFlags, fragmentPolicy);
-    // TODO(wangxianzhu): We may paint a layer multiple times with different flags.
-    // The following ensures the flag is only cleared once after the last painting.
-    // This is fragile but is temporary for spv1.
-    if (paintFlags & PaintLayerPaintingCompositingForegroundPhase)
-        m_paintLayer.clearNeedsRepaint();
-    return result;
-}
-
-PaintLayerPainter::PaintResult PaintLayerPainter::paintLayerContentsInternal(GraphicsContext* context, const PaintLayerPaintingInfo& paintingInfoArg, PaintLayerFlags paintFlags, FragmentPolicy fragmentPolicy)
+PaintLayerPainter::PaintResult PaintLayerPainter::paintLayerContents(GraphicsContext* context, const PaintLayerPaintingInfo& paintingInfoArg, PaintLayerFlags paintFlags, FragmentPolicy fragmentPolicy)
 {
     ASSERT(m_paintLayer.isSelfPaintingLayer() || m_paintLayer.hasSelfPaintingLayerDescendant());
     ASSERT(!(paintFlags & PaintLayerAppliedTransform));
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.h b/third_party/WebKit/Source/core/paint/PaintLayerPainter.h
index 26f4758..05095cc 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.h
@@ -46,8 +46,6 @@
 private:
     enum ClipState { HasNotClipped, HasClipped };
 
-    PaintResult paintLayerInternal(GraphicsContext*, const PaintLayerPaintingInfo&, PaintLayerFlags);
-    PaintResult paintLayerContentsInternal(GraphicsContext*, const PaintLayerPaintingInfo&, PaintLayerFlags, FragmentPolicy = AllowMultipleFragments);
     PaintResult paintLayerContentsAndReflection(GraphicsContext*, const PaintLayerPaintingInfo&, PaintLayerFlags, FragmentPolicy = AllowMultipleFragments);
     PaintResult paintLayerWithTransform(GraphicsContext*, const PaintLayerPaintingInfo&, PaintLayerFlags);
     PaintResult paintFragmentByApplyingTransform(GraphicsContext*, const PaintLayerPaintingInfo&, PaintLayerFlags, const LayoutPoint& fragmentTranslation);
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
index c7e5fd91..b5f81f7 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
@@ -26,7 +26,7 @@
 
 TEST_P(PaintLayerPainterTest, CachedSubsequence)
 {
-    RuntimeEnabledFeatures::setSlimmingPaintSubsequenceCachingEnabled(true);
+    RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(true);
 
     setBodyInnerHTML(
         "<div id='container1' style='position: relative; z-index: 1; width: 200px; height: 200px; background-color: blue'>"
@@ -47,11 +47,6 @@
     PaintLayer& container2Layer = *toLayoutBoxModelObject(container2).layer();
     LayoutObject& content2 = *document().getElementById("content2")->layoutObject();
 
-    GraphicsContext context(&rootPaintController());
-    PaintLayerPaintingInfo paintingInfo(&rootLayer, LayoutRect(0, 0, 800, 600), GlobalPaintNormalPhase, LayoutSize());
-    PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases);
-    rootPaintController().commitNewDisplayItems();
-
     if (rootLayerScrolls) {
         EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 11,
             TestDisplayItem(layoutView(), backgroundType),
@@ -84,73 +79,6 @@
 
     toHTMLElement(content1.node())->setAttribute(HTMLNames::styleAttr, "position: absolute; width: 100px; height: 100px; background-color: green");
     document().view()->updateAllLifecyclePhases();
-    PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases);
-
-    if (rootLayerScrolls) {
-        EXPECT_DISPLAY_LIST(rootPaintController().newDisplayItemList(), 9,
-            TestDisplayItem(layoutView(), cachedBackgroundType),
-            TestDisplayItem(rootLayer, subsequenceType),
-            TestDisplayItem(container1, cachedBackgroundType),
-            TestDisplayItem(container1Layer, subsequenceType),
-            TestDisplayItem(content1, backgroundType),
-            TestDisplayItem(container1Layer, endSubsequenceType),
-            TestDisplayItem(container2, cachedBackgroundType),
-            TestDisplayItem(container2Layer, cachedSubsequenceType),
-            TestDisplayItem(rootLayer, endSubsequenceType));
-    } else {
-        EXPECT_DISPLAY_LIST(rootPaintController().newDisplayItemList(), 11,
-            TestDisplayItem(layoutView(), cachedBackgroundType),
-            TestDisplayItem(rootLayer, subsequenceType),
-            TestDisplayItem(htmlLayer, subsequenceType),
-            TestDisplayItem(container1, cachedBackgroundType),
-            TestDisplayItem(container1Layer, subsequenceType),
-            TestDisplayItem(content1, backgroundType),
-            TestDisplayItem(container1Layer, endSubsequenceType),
-            TestDisplayItem(container2, cachedBackgroundType),
-            TestDisplayItem(container2Layer, cachedSubsequenceType),
-            TestDisplayItem(htmlLayer, endSubsequenceType),
-            TestDisplayItem(rootLayer, endSubsequenceType));
-    }
-
-    rootPaintController().commitNewDisplayItems();
-
-    if (rootLayerScrolls) {
-        EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 11,
-            TestDisplayItem(layoutView(), backgroundType),
-            TestDisplayItem(rootLayer, subsequenceType),
-            TestDisplayItem(container1, backgroundType),
-            TestDisplayItem(container1Layer, subsequenceType),
-            TestDisplayItem(content1, backgroundType),
-            TestDisplayItem(container1Layer, endSubsequenceType),
-            TestDisplayItem(container2, backgroundType),
-            TestDisplayItem(container2Layer, subsequenceType),
-            TestDisplayItem(content2, backgroundType),
-            TestDisplayItem(container2Layer, endSubsequenceType),
-            TestDisplayItem(rootLayer, endSubsequenceType));
-    } else {
-        EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 13,
-            TestDisplayItem(layoutView(), backgroundType),
-            TestDisplayItem(rootLayer, subsequenceType),
-            TestDisplayItem(htmlLayer, subsequenceType),
-            TestDisplayItem(container1, backgroundType),
-            TestDisplayItem(container1Layer, subsequenceType),
-            TestDisplayItem(content1, backgroundType),
-            TestDisplayItem(container1Layer, endSubsequenceType),
-            TestDisplayItem(container2, backgroundType),
-            TestDisplayItem(container2Layer, subsequenceType),
-            TestDisplayItem(content2, backgroundType),
-            TestDisplayItem(container2Layer, endSubsequenceType),
-            TestDisplayItem(htmlLayer, endSubsequenceType),
-            TestDisplayItem(rootLayer, endSubsequenceType));
-    }
-
-    // Repeated painting should just generate the root cached subsequence.
-    PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases);
-    EXPECT_DISPLAY_LIST(rootPaintController().newDisplayItemList(), 2,
-        TestDisplayItem(layoutView(), cachedBackgroundType),
-        TestDisplayItem(rootLayer, cachedSubsequenceType));
-
-    rootPaintController().commitNewDisplayItems();
 
     if (rootLayerScrolls) {
         EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 11,
@@ -185,7 +113,7 @@
 
 TEST_P(PaintLayerPainterTest, CachedSubsequenceOnInterestRectChange)
 {
-    RuntimeEnabledFeatures::setSlimmingPaintSubsequenceCachingEnabled(true);
+    RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(true);
 
     setBodyInnerHTML(
         "<div id='container1' style='position: relative; z-index: 1; width: 200px; height: 200px; background-color: blue'>"
@@ -213,11 +141,8 @@
     PaintLayer& container3Layer = *toLayoutBoxModelObject(container3).layer();
     LayoutObject& content3 = *document().getElementById("content3")->layoutObject();
 
-    document().view()->updateAllLifecyclePhases();
-    GraphicsContext context(&rootPaintController());
-    PaintLayerPaintingInfo paintingInfo(&rootLayer, LayoutRect(0, 0, 400, 300), GlobalPaintNormalPhase, LayoutSize());
-    PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases);
-    rootPaintController().commitNewDisplayItems();
+    LayoutRect interestRect(0, 0, 400, 300);
+    document().view()->updateAllLifecyclePhases(&interestRect);
 
     // Container1 is fully in the interest rect;
     // Container2 is partly (including its stacking chidren) in the interest rect;
@@ -261,43 +186,14 @@
             TestDisplayItem(rootLayer, endSubsequenceType));
     }
 
+    LayoutRect newInterestRect(0, 100, 300, 300);
+    document().view()->updateAllLifecyclePhases(&newInterestRect);
+
     // Container1 becomes partly in the interest rect, but uses cached subsequence
     // because it was fully painted before;
     // Container2's intersection with the interest rect changes;
     // Content2b is out of the interest rect and outputs nothing;
     // Container3 becomes out of the interest rect and outputs nothing.
-    PaintLayerPaintingInfo paintingInfo1(&rootLayer, LayoutRect(0, 100, 300, 300), GlobalPaintNormalPhase, LayoutSize());
-    PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo1, PaintLayerPaintingCompositingAllPhases);
-
-    if (rootLayerScrolls) {
-        EXPECT_DISPLAY_LIST(rootPaintController().newDisplayItemList(), 9,
-            TestDisplayItem(layoutView(), cachedBackgroundType),
-            TestDisplayItem(rootLayer, subsequenceType),
-            TestDisplayItem(container1, cachedBackgroundType),
-            TestDisplayItem(container1Layer, cachedSubsequenceType),
-            TestDisplayItem(container2, cachedBackgroundType),
-            TestDisplayItem(container2Layer, subsequenceType),
-            TestDisplayItem(content2a, cachedBackgroundType),
-            TestDisplayItem(container2Layer, endSubsequenceType),
-            TestDisplayItem(rootLayer, endSubsequenceType));
-
-    } else {
-        EXPECT_DISPLAY_LIST(rootPaintController().newDisplayItemList(), 11,
-            TestDisplayItem(layoutView(), cachedBackgroundType),
-            TestDisplayItem(rootLayer, subsequenceType),
-            TestDisplayItem(htmlLayer, subsequenceType),
-            TestDisplayItem(container1, cachedBackgroundType),
-            TestDisplayItem(container1Layer, cachedSubsequenceType),
-            TestDisplayItem(container2, cachedBackgroundType),
-            TestDisplayItem(container2Layer, subsequenceType),
-            TestDisplayItem(content2a, cachedBackgroundType),
-            TestDisplayItem(container2Layer, endSubsequenceType),
-            TestDisplayItem(htmlLayer, endSubsequenceType),
-            TestDisplayItem(rootLayer, endSubsequenceType));
-    }
-
-    rootPaintController().commitNewDisplayItems();
-
     if (rootLayerScrolls) {
         EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 11,
             TestDisplayItem(layoutView(), backgroundType),
diff --git a/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp b/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp
index 5cc82e8..ddd2b52b 100644
--- a/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp
@@ -28,7 +28,7 @@
 
     // Create a new context so the contents of the filter can be drawn and cached.
     m_paintController = PaintController::create();
-    m_context = adoptPtr(new GraphicsContext(m_paintController.get()));
+    m_context = adoptPtr(new GraphicsContext(*m_paintController));
     context = m_context.get();
 
     filterData->m_state = FilterData::RecordingContent;
diff --git a/third_party/WebKit/Source/core/paint/TableCellPainterTest.cpp b/third_party/WebKit/Source/core/paint/TableCellPainterTest.cpp
index 9b38f56..a1f9120 100644
--- a/third_party/WebKit/Source/core/paint/TableCellPainterTest.cpp
+++ b/third_party/WebKit/Source/core/paint/TableCellPainterTest.cpp
@@ -31,7 +31,7 @@
     LayoutObject& cell1 = *document().getElementById("cell1")->layoutObject();
     LayoutObject& cell2 = *document().getElementById("cell2")->layoutObject();
 
-    GraphicsContext context(&rootPaintController());
+    GraphicsContext context(rootPaintController());
     PaintLayerPaintingInfo paintingInfo(&rootLayer, LayoutRect(0, 0, 200, 200), GlobalPaintNormalPhase, LayoutSize());
     PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases);
     rootPaintController().commitNewDisplayItems();
diff --git a/third_party/WebKit/Source/devtools/devtools.gypi b/third_party/WebKit/Source/devtools/devtools.gypi
index 74cbe9c..74959fc 100644
--- a/third_party/WebKit/Source/devtools/devtools.gypi
+++ b/third_party/WebKit/Source/devtools/devtools.gypi
@@ -574,7 +574,7 @@
             'front_end/script_formatter_worker/ScriptFormatterWorker.js',
         ],
         'devtools_settings_js_files': [
-            'front_end/settings/EditFileSystemDialog.js',
+            'front_end/settings/EditFileSystemView.js',
             'front_end/settings/FrameworkBlackboxSettingsTab.js',
             'front_end/settings/SettingsScreen.js',
         ],
diff --git a/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilitySidebarView.js b/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilitySidebarView.js
index 61a8cd4..9dd59f6 100644
--- a/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilitySidebarView.js
+++ b/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilitySidebarView.js
@@ -494,7 +494,8 @@
      */
     appendRelationshipValueElement: function(value)
     {
-        var deferredNode = new WebInspector.DeferredDOMNode(this._target, value.relatedNodeValue.backendNodeId);
+        var relatedNode = value.relatedNodes[0];
+        var deferredNode = new WebInspector.DeferredDOMNode(this._target, relatedNode.backendNodeId);
         var valueElement = createElement("span");
 
         /**
@@ -503,8 +504,8 @@
         function onNodeResolved(node)
         {
             valueElement.appendChild(WebInspector.DOMPresentationUtils.linkifyNodeReference(node));
-            if (value.relatedNodeValue.text) {
-                var textElement = WebInspector.AccessibilitySidebarView.createSimpleValueElement(AccessibilityAgent.AXValueType.ComputedString, value.relatedNodeValue.text);
+            if (relatedNode.text) {
+                var textElement = WebInspector.AccessibilitySidebarView.createSimpleValueElement(AccessibilityAgent.AXValueType.ComputedString, relatedNode.text);
                 valueElement.appendChild(textElement);
             }
         }
@@ -518,7 +519,7 @@
      */
     appendRelatedNodeListValueElement: function(value)
     {
-        var relatedNodes = value.relatedNodeArrayValue;
+        var relatedNodes = value.relatedNodes;
         var numNodes = relatedNodes.length;
         var valueElement;
         if (value.type === AccessibilityAgent.AXValueType.IdrefList) {
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
index 123fa1e..0909a0c 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
@@ -261,11 +261,9 @@
 
         if (!this.selectionElement) {
             this.selectionElement = createElement("div");
-            this.selectionElement.className = "selection selected";
+            this.selectionElement.className = "selection fill";
             listItemElement.insertBefore(this.selectionElement, listItemElement.firstChild);
         }
-
-        this.selectionElement.style.height = listItemElement.offsetHeight + "px";
     },
 
     /**
@@ -1100,8 +1098,19 @@
 
     updateDecorations: function()
     {
+        var treeElement = this.parent;
+        var depth = 0;
+        while (treeElement != null) {
+            depth++;
+            treeElement = treeElement.parent;
+        }
+
+        /** Keep it in sync with elementsTreeOutline.css **/
+        this._gutterContainer.style.left = (-12 * (depth - 2) - (this.isExpandable() ? 1 : 12)) + "px";
+
         if (this.isClosingTag())
             return;
+
         var node = this._node;
         if (node.nodeType() !== Node.ELEMENT_NODE)
             return;
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js
index 5d399ba6..e3345a7 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js
@@ -1790,7 +1790,7 @@
 WebInspector.ElementsTreeOutline.ShortcutTreeElement = function(nodeShortcut)
 {
     TreeElement.call(this, "");
-    this.listItemElement.createChild("div", "selection");
+    this.listItemElement.createChild("div", "selection fill");
     var title = this.listItemElement.createChild("span", "elements-tree-shortcut-title");
     var text = nodeShortcut.nodeName.toLowerCase();
     if (nodeShortcut.nodeType === Node.ELEMENT_NODE)
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css b/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
index a4967ea..5c4d93f7 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
+++ b/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
@@ -11,13 +11,16 @@
 }
 
 .elements-disclosure li {
+    /** Keep margin-left & padding-left in sync with ElementsTreeElements.updateDecorators **/
     padding: 0 0 0 14px;
     margin-top: 1px;
     margin-left: -2px;
     word-wrap: break-word;
+    position: relative;
 }
 
 .elements-disclosure li.parent {
+    /** Keep it in sync with ElementsTreeElements.updateDecorators **/
     margin-left: -13px;
 }
 
@@ -54,11 +57,8 @@
 
 .elements-disclosure li .selection {
     display: none;
-    position: absolute;
-    left: 0;
-    right: 0;
-    height: 15px;
     z-index: -1;
+    margin-left: -10000px;
 }
 
 .elements-disclosure li.hovered:not(.selected) .selection {
@@ -80,6 +80,7 @@
 
 .elements-disclosure ol {
     list-style-type: none;
+    /** Keep it in sync with ElementsTreeElements.updateDecorators **/
     -webkit-padding-start: 12px;
     margin: 0;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/inspectorStyle.css b/third_party/WebKit/Source/devtools/front_end/inspectorStyle.css
index ecf126de..27e1017a 100644
--- a/third_party/WebKit/Source/devtools/front_end/inspectorStyle.css
+++ b/third_party/WebKit/Source/devtools/front_end/inspectorStyle.css
@@ -135,6 +135,10 @@
     margin: 0;
 }
 
+.outline-disclosure li {
+    position: relative;
+}
+
 .outline-disclosure li.hovered:not(.selected) .selection {
     display: block;
     left: 3px;
@@ -145,11 +149,8 @@
 
 .outline-disclosure li .selection {
     display: none;
-    position: absolute;
-    left: 0;
-    right: 0;
-    height: 15px;
     z-index: -1;
+    margin-left: -10000px;
 }
 
 .outline-disclosure li.selected .selection {
@@ -192,7 +193,6 @@
     margin-top: 1px;
     text-overflow: ellipsis;
     white-space: nowrap;
-    overflow: hidden;
 }
 
 ol.outline-disclosure:focus li.selected {
@@ -608,4 +608,4 @@
     box-shadow: 0 1px 0 rgba(80, 80, 80, 0.08),
     inset 0 1px 2px rgba(255, 255, 255, 0.75);
     color: #aaa;
-}
\ No newline at end of file
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/FileSystemView.js b/third_party/WebKit/Source/devtools/front_end/resources/FileSystemView.js
index dc6786e..d372176 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/FileSystemView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/FileSystemView.js
@@ -128,7 +128,7 @@
      */
     onattach: function()
     {
-        var selection = this.listItemElement.createChild("div", "selection");
+        var selection = this.listItemElement.createChild("div", "selection fill");
         this.listItemElement.insertBefore(selection, this.listItemElement.firstChild);
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
index f909238..60d574f 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
@@ -853,7 +853,7 @@
                 this.listItemElement.classList.add(this._iconClasses[i]);
         }
 
-        this.listItemElement.createChild("div", "selection");
+        this.listItemElement.createChild("div", "selection fill");
 
         if (!this._noIcon)
             this.imageElement = this.listItemElement.createChild("img", "icon");
diff --git a/third_party/WebKit/Source/devtools/front_end/settings/EditFileSystemDialog.js b/third_party/WebKit/Source/devtools/front_end/settings/EditFileSystemView.js
similarity index 93%
rename from third_party/WebKit/Source/devtools/front_end/settings/EditFileSystemDialog.js
rename to third_party/WebKit/Source/devtools/front_end/settings/EditFileSystemView.js
index de2647b..ae658b8 100644
--- a/third_party/WebKit/Source/devtools/front_end/settings/EditFileSystemDialog.js
+++ b/third_party/WebKit/Source/devtools/front_end/settings/EditFileSystemView.js
@@ -33,16 +33,12 @@
  * @extends {WebInspector.VBox}
  * @param {string} fileSystemPath
  */
-WebInspector.EditFileSystemDialog = function(fileSystemPath)
+WebInspector.EditFileSystemView = function(fileSystemPath)
 {
     WebInspector.VBox.call(this);
     this.element.classList.add("dialog-contents", "settings-dialog", "settings-tab");
     this._fileSystemPath = fileSystemPath;
 
-    var header = this.element.createChild("div", "header");
-    var headerText = header.createChild("span");
-    headerText.textContent = WebInspector.UIString("Edit file system");
-
     var contents = this.element.createChild("div", "contents");
 
     WebInspector.fileSystemMapping.addEventListener(WebInspector.FileSystemMapping.Events.FileMappingAdded, this._fileMappingAdded, this);
@@ -77,7 +73,7 @@
             this._addMappingRow(entry);
     }
 
-    blockHeader = contents.createChild("div", "block-header");
+    blockHeader = contents.createChild("div", "block-header excluded-folders-header");
     blockHeader.textContent = WebInspector.UIString("Excluded folders");
     this._excludedFolderListSection = contents.createChild("div", "section excluded-folders-section");
     this._excludedFolderListContainer = this._excludedFolderListSection.createChild("div", "settings-list-container");
@@ -95,21 +91,17 @@
 
     this.element.tabIndex = 0;
     this._hasMappingChanges = false;
-
-    this._dialog = new WebInspector.Dialog();
-    this._dialog.setWrapsContent(true);
-    this._dialog.setMaxSize(new Size(600, 600));
-    this._dialog.addCloseButton();
-    this.show(this._dialog.element);
-    this._dialog.show();
 }
 
-WebInspector.EditFileSystemDialog.show = function(fileSystemPath)
-{
-    new WebInspector.EditFileSystemDialog(fileSystemPath);
-}
+WebInspector.EditFileSystemView.prototype = {
+    dispose: function()
+    {
+        WebInspector.fileSystemMapping.removeEventListener(WebInspector.FileSystemMapping.Events.FileMappingAdded, this._fileMappingAdded, this);
+        WebInspector.fileSystemMapping.removeEventListener(WebInspector.FileSystemMapping.Events.FileMappingRemoved, this._fileMappingRemoved, this);
+        WebInspector.isolatedFileSystemManager.removeEventListener(WebInspector.IsolatedFileSystemManager.Events.ExcludedFolderAdded, this._excludedFolderAdded, this);
+        WebInspector.isolatedFileSystemManager.removeEventListener(WebInspector.IsolatedFileSystemManager.Events.ExcludedFolderRemoved, this._excludedFolderRemoved, this);
+    },
 
-WebInspector.EditFileSystemDialog.prototype = {
     _fileMappingAdded: function(event)
     {
         var entry = /** @type {!WebInspector.FileSystemMapping.Entry} */ (event.data);
@@ -125,8 +117,6 @@
         delete this._entries[key];
         if (this._fileMappingsList.itemForId(key))
             this._fileMappingsList.removeItem(key);
-        if (this._dialog)
-            this._dialog.contentResized();
     },
 
     /**
@@ -256,8 +246,6 @@
         this._entries[key] = entry;
         var keys = Object.keys(this._entries).sort();
         this._fileMappingsList.addItem(key, keys[keys.indexOf(key) + 1], !entry.configurable);
-        if (this._dialog)
-            this._dialog.contentResized();
     },
 
     /**
@@ -350,8 +338,6 @@
         // Insert configurable entries before non-configurable.
         var insertBefore = readOnly ? null : this._firstNonConfigurableExcludedFolder;
         this._excludedFolderList.addItem(readOnly ? WebInspector.UIString("%s (via .devtools)", path) : path, insertBefore, readOnly);
-        if (this._dialog)
-            this._dialog.contentResized();
     },
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js b/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js
index ea7b2512..453815a5 100644
--- a/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js
+++ b/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js
@@ -327,99 +327,47 @@
     this._addFileSystemRowElement = this._fileSystemsSection.createChild("div");
     this._addFileSystemRowElement.appendChild(createTextButton(WebInspector.UIString("Add folder\u2026"), this._addFileSystemClicked.bind(this)));
 
-    this._editFileSystemButton = createTextButton(WebInspector.UIString("Folder options\u2026"), this._editFileSystemClicked.bind(this));
-    this._addFileSystemRowElement.appendChild(this._editFileSystemButton);
-    this._updateEditFileSystemButtonState();
+    /** @type {!Map<string, !Element>} */
+    this._elementByPath = new Map();
 
-    this._reset();
+    /** @type {!Map<string, !WebInspector.EditFileSystemView>} */
+    this._mappingViewByPath = new Map();
+
+    var fileSystemPaths = WebInspector.isolatedFileSystemManager.fileSystemPaths();
+    for (var i = 0; i < fileSystemPaths.length; ++i)
+        this._addItem(/** @type {!WebInspector.IsolatedFileSystem} */ (WebInspector.isolatedFileSystemManager.fileSystem(fileSystemPaths[i])));
 }
 
 WebInspector.WorkspaceSettingsTab.prototype = {
-    wasShown: function()
+    /**
+     * @param {!WebInspector.IsolatedFileSystem} fileSystem
+     */
+    _addItem: function(fileSystem)
     {
-        WebInspector.SettingsTab.prototype.wasShown.call(this);
-        this._reset();
-    },
+        var element = this._renderFileSystem(fileSystem);
+        this._elementByPath.set(fileSystem.path(), element);
 
-    _reset: function()
-    {
-        this._resetFileSystems();
-    },
+        this._fileSystemsListContainer.appendChild(element);
 
-    _resetFileSystems: function()
-    {
-        this._fileSystemsListContainer.removeChildren();
-        var fileSystemPaths = WebInspector.isolatedFileSystemManager.fileSystemPaths();
-        delete this._fileSystemsList;
-
-        if (!fileSystemPaths.length) {
-            var noFileSystemsMessageElement = this._fileSystemsListContainer.createChild("div", "no-file-systems-message");
-            noFileSystemsMessageElement.textContent = WebInspector.UIString("You have no file systems added.");
-            return;
-        }
-
-        this._fileSystemsList = new WebInspector.SettingsList([{ id: "path" }], this._renderFileSystem.bind(this));
-        this._fileSystemsList.element.classList.add("file-systems-list");
-        this._fileSystemsList.addEventListener(WebInspector.SettingsList.Events.Selected, this._fileSystemSelected.bind(this));
-        this._fileSystemsList.addEventListener(WebInspector.SettingsList.Events.Removed, this._fileSystemRemovedfromList.bind(this));
-        this._fileSystemsList.addEventListener(WebInspector.SettingsList.Events.DoubleClicked, this._fileSystemDoubleClicked.bind(this));
-        this._fileSystemsListContainer.appendChild(this._fileSystemsList.element);
-        for (var i = 0; i < fileSystemPaths.length; ++i)
-            this._fileSystemsList.addItem(fileSystemPaths[i]);
-        this._updateEditFileSystemButtonState();
-    },
-
-    _updateEditFileSystemButtonState: function()
-    {
-        this._editFileSystemButton.disabled = !this._selectedFileSystemPath();
+        var mappingView = new WebInspector.EditFileSystemView(fileSystem.path());
+        this._mappingViewByPath.set(fileSystem.path(), mappingView);
+        mappingView.show(element);
     },
 
     /**
-     * @param {!WebInspector.Event} event
+     * @param {!WebInspector.IsolatedFileSystem} fileSystem
+     * @return {!Element}
      */
-    _fileSystemSelected: function(event)
+    _renderFileSystem: function(fileSystem)
     {
-        this._updateEditFileSystemButtonState();
-    },
-
-    /**
-     * @param {!WebInspector.Event} event
-     */
-    _fileSystemDoubleClicked: function(event)
-    {
-        var id = /** @type{?string} */ (event.data);
-        this._editFileSystem(id);
-    },
-
-    _editFileSystemClicked: function()
-    {
-        this._editFileSystem(this._selectedFileSystemPath());
-    },
-
-    /**
-     * @param {?string} id
-     */
-    _editFileSystem: function(id)
-    {
-        WebInspector.EditFileSystemDialog.show(id);
-    },
-
-    /**
-     * @param {!Element} columnElement
-     * @param {{id: string, placeholder: (string|undefined), options: (!Array.<string>|undefined)}} column
-     * @param {?string} id
-     */
-    _renderFileSystem: function(columnElement, column, id)
-    {
-        if (!id)
-            return "";
-        var fileSystemPath = id;
-        var textElement = columnElement.createChild("span", "list-column-text");
-        var pathElement = textElement.createChild("span", "file-system-path");
+        var element = createElementWithClass("div", "file-system-container");
+        var fileSystemPath = fileSystem.path();
+        var textElement = element.createChild("div", "file-system-header");
+        var pathElement = textElement.createChild("div", "file-system-path");
         pathElement.title = fileSystemPath;
 
-        const maxTotalPathLength = 55;
-        const maxFolderNameLength = 30;
+        const maxTotalPathLength = 75;
+        const maxFolderNameLength = 40;
 
         var lastIndexOfSlash = fileSystemPath.lastIndexOf(WebInspector.isWin() ? "\\" : "/");
         var folderName = fileSystemPath.substr(lastIndexOfSlash + 1);
@@ -427,22 +375,25 @@
         folderPath = folderPath.trimMiddle(maxTotalPathLength - Math.min(maxFolderNameLength, folderName.length));
         folderName = folderName.trimMiddle(maxFolderNameLength);
 
+        pathElement.createChild("span").textContent = WebInspector.UIString("Folder: ");
+
         var folderPathElement = pathElement.createChild("span");
         folderPathElement.textContent = folderPath;
 
         var nameElement = pathElement.createChild("span", "file-system-path-name");
         nameElement.textContent = folderName;
+
+        textElement.appendChild(createTextButton(WebInspector.UIString("Remove"), this._removeFileSystemClicked.bind(this, fileSystem)));
+
+        return element;
     },
 
     /**
-     * @param {!WebInspector.Event} event
+     * @param {!WebInspector.IsolatedFileSystem} fileSystem
      */
-    _fileSystemRemovedfromList: function(event)
+    _removeFileSystemClicked: function(fileSystem)
     {
-        var id = /** @type{?string} */ (event.data);
-        if (!id)
-            return;
-        WebInspector.isolatedFileSystemManager.removeFileSystem(id);
+        WebInspector.isolatedFileSystemManager.removeFileSystem(fileSystem.path());
     },
 
     _addFileSystemClicked: function()
@@ -453,25 +404,24 @@
     _fileSystemAdded: function(event)
     {
         var fileSystem = /** @type {!WebInspector.IsolatedFileSystem} */ (event.data);
-        if (!this._fileSystemsList)
-            this._reset();
-        else
-            this._fileSystemsList.addItem(fileSystem.path());
+        this._addItem(fileSystem);
     },
 
     _fileSystemRemoved: function(event)
     {
         var fileSystem = /** @type {!WebInspector.IsolatedFileSystem} */ (event.data);
-        if (this._fileSystemsList.itemForId(fileSystem.path()))
-            this._fileSystemsList.removeItem(fileSystem.path());
-        if (!this._fileSystemsList.itemIds().length)
-            this._reset();
-        this._updateEditFileSystemButtonState();
-    },
 
-    _selectedFileSystemPath: function()
-    {
-        return this._fileSystemsList ? this._fileSystemsList.selectedId() : null;
+        var mappingView = this._mappingViewByPath.get(fileSystem.path());
+        if (mappingView) {
+            mappingView.dispose();
+            this._mappingViewByPath.delete(fileSystem.path());
+        }
+
+        var element = this._elementByPath.get(fileSystem.path());
+        if (element) {
+            this._elementByPath.delete(fileSystem.path());
+            element.remove();
+        }
     },
 
     __proto__: WebInspector.SettingsTab.prototype
diff --git a/third_party/WebKit/Source/devtools/front_end/settings/module.json b/third_party/WebKit/Source/devtools/front_end/settings/module.json
index 3346d00..2f7cd7e 100644
--- a/third_party/WebKit/Source/devtools/front_end/settings/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/settings/module.json
@@ -51,7 +51,7 @@
         "components"
     ],
     "scripts": [
-        "EditFileSystemDialog.js",
+        "EditFileSystemView.js",
         "SettingsScreen.js",
         "FrameworkBlackboxSettingsTab.js"
     ]
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
index cf00c39..38f03e3 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
@@ -669,7 +669,7 @@
                 this.listItemElement.classList.add(this._iconClasses[i]);
         }
 
-        this.listItemElement.createChild("div", "selection");
+        this.listItemElement.createChild("div", "selection fill");
 
         if (!this._noIcon)
             this.imageElement = this.listItemElement.createChild("img", "icon");
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css b/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css
index 8eba492c8..85119fa 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css
+++ b/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css
@@ -69,10 +69,6 @@
     color: white;
 }
 
-.navigator li.selected .selection {
-    height: 18px;
-}
-
 .navigator > ol.being-edited li.selected .selection {
     background-color: rgb(56, 121, 217);
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/helpScreen.css b/third_party/WebKit/Source/devtools/front_end/ui/helpScreen.css
index 1078170..03be39c 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/helpScreen.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/helpScreen.css
@@ -315,11 +315,6 @@
     margin-right: 20px;
 }
 
-.settings-tab .settings-list-container {
-    background-color: white;
-    margin-bottom: 10px;
-}
-
 .settings-tab .settings-list {
     border: 1px solid hsl(0, 0%, 85%);
     border-radius: 2px;
@@ -443,16 +438,30 @@
     margin-left: 0;
 }
 
-.settings-tab .settings-list .settings-list-item .file-system-path {
+.settings-tab .file-system-container {
+    margin-bottom: 20px;
+}
+
+.settings-tab .file-system-header {
+    display: flex;
+    flex-direction: row;
+    align-items: baseline;
+}
+
+.settings-tab .file-system-path {
     white-space: nowrap;
-    font-size: 12px;
-    padding-left: 6px;
+    font-size: 1.4em;
     padding-right: 5px;
     -webkit-box-flex: 1;
     color: hsl(210, 16%, 22%);
+    margin-bottom: 8px;
+    overflow: hidden;
+    flex: 0 1 auto;
+    margin-right: 5px;
+    text-overflow: ellipsis;
 }
 
-.settings-tab .settings-list .settings-list-item .file-system-path-name {
+.settings-tab .file-system-path-name {
     padding-right: 6px;
     font-weight: bold;
 }
@@ -481,6 +490,10 @@
     width: 20%;
 }
 
+.excluded-folders-header {
+    margin-top: 10px;
+}
+
 .excluded-folders-list .settings-list-item .list-column.settings-list-column-path {
     width: 100%;
 }
@@ -493,7 +506,6 @@
 .settings-dialog {
     display: -webkit-flex;
     -webkit-flex-direction: column;
-    background: white;
 }
 
 .settings-dialog .dialog-contents {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css
index 53b1e380..f7f6ce0 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css
@@ -21,12 +21,9 @@
 
 .tree-outline li .selection {
     display: none;
-    position: absolute;
-    left: 0;
-    right: 0;
-    height: 17px;
     z-index: -1;
     margin-top: -1px;
+    margin-left: -10000px;
 }
 
 .tree-outline li.selected .selection {
@@ -71,6 +68,7 @@
     overflow: hidden;
     min-height: 17px;
     padding-top: 2px;
+    position: relative;
 }
 
 ol.tree-outline:focus li.selected {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
index e43d1437..c8f4645 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
@@ -693,7 +693,7 @@
         if (!this.treeOutline || !this.treeOutline._renderSelection)
             return;
         if (!this._selectionElement)
-            this._selectionElement = createElementWithClass("div", "selection");
+            this._selectionElement = createElementWithClass("div", "selection fill");
         this._listItemNode.insertBefore(this._selectionElement, this.listItemElement.firstChild);
     },
 
@@ -914,8 +914,6 @@
             return false;
         this.treeOutline.selectedTreeElement = this;
         this._listItemNode.classList.add("selected");
-        if (this._selectionElement)
-            this._selectionElement.style.height = this._listItemNode.offsetHeight + "px";
         this.treeOutline.dispatchEventToListeners(TreeOutline.Events.ElementSelected, this);
         return this.onselect(selectedByUser);
     },
diff --git a/third_party/WebKit/Source/devtools/protocol.json b/third_party/WebKit/Source/devtools/protocol.json
index adf6e9b..db8074c1 100644
--- a/third_party/WebKit/Source/devtools/protocol.json
+++ b/third_party/WebKit/Source/devtools/protocol.json
@@ -5189,8 +5189,7 @@
                     { "name": "type", "$ref": "AXValueType", "description": "The type of this value." },
 
                     { "name": "value", "type": "any", "description": "The computed value of this property.", "optional": true },
-                    { "name": "relatedNodeValue", "$ref": "AXRelatedNode", "description": "The related node value, if any.", "optional": true },
-                    { "name": "relatedNodeArrayValue", "type": "array", "items": { "$ref": "AXRelatedNode" }, "description": "Multiple relted nodes, if applicable.", "optional": true },
+                    { "name": "relatedNodes", "type": "array", "items": { "$ref": "AXRelatedNode" }, "description": "One or more related nodes, if applicable.", "optional": true },
                     { "name": "sources", "type": "array", "items": { "$ref": "AXValueSource" }, "description": "The sources which contributed to the computation of this property.", "optional": true }
                 ],
                 "description": "A single computed AX property."
diff --git a/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp b/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
index 79a81d3..541b8df1 100644
--- a/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
@@ -69,7 +69,7 @@
     properties->addItem(createProperty(AXLiveRegionAttributes::Busy, createBooleanValue(axObject->containerLiveRegionBusy())));
 
     if (!axObject->isLiveRegion())
-        properties->addItem(createProperty(AXLiveRegionAttributes::Root, createRelatedNodeValue(axObject->liveRegionRoot())));
+        properties->addItem(createProperty(AXLiveRegionAttributes::Root, createRelatedNodeListValue(axObject->liveRegionRoot())));
 }
 
 void fillGlobalStates(AXObject* axObject, PassRefPtr<TypeBuilder::Array<AXProperty>> properties)
@@ -79,7 +79,7 @@
 
     if (const AXObject* hiddenRoot = axObject->ariaHiddenRoot()) {
         properties->addItem(createProperty(AXGlobalStates::Hidden, createBooleanValue(true)));
-        properties->addItem(createProperty(AXGlobalStates::HiddenRoot, createRelatedNodeValue(hiddenRoot)));
+        properties->addItem(createProperty(AXGlobalStates::HiddenRoot, createRelatedNodeListValue(hiddenRoot)));
     }
 
     InvalidState invalidState = axObject->invalidState();
@@ -258,7 +258,7 @@
 void fillRelationships(AXObject* axObject, PassRefPtr<TypeBuilder::Array<AXProperty>> properties)
 {
     if (AXObject* activeDescendant = axObject->activeDescendant()) {
-        properties->addItem(createProperty(AXRelationshipAttributes::Activedescendant, createRelatedNodeValue(activeDescendant)));
+        properties->addItem(createProperty(AXRelationshipAttributes::Activedescendant, createRelatedNodeListValue(activeDescendant)));
     }
 
     AXObject::AXObjectVector results;
diff --git a/third_party/WebKit/Source/modules/accessibility/InspectorTypeBuilderHelper.cpp b/third_party/WebKit/Source/modules/accessibility/InspectorTypeBuilderHelper.cpp
index 0e7c8100..f5c8c59 100644
--- a/third_party/WebKit/Source/modules/accessibility/InspectorTypeBuilderHelper.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/InspectorTypeBuilderHelper.cpp
@@ -92,7 +92,7 @@
 PassRefPtr<AXProperty> createProperty(IgnoredReason reason)
 {
     if (reason.relatedObject)
-        return createProperty(ignoredReasonName(reason.reason), createRelatedNodeValue(reason.relatedObject, nullptr, AXValueType::Idref));
+        return createProperty(ignoredReasonName(reason.reason), createRelatedNodeListValue(reason.relatedObject, nullptr, AXValueType::Idref));
     return createProperty(ignoredReasonName(reason.reason), createBooleanValue(true));
 }
 
@@ -146,11 +146,13 @@
     return relatedNode;
 }
 
-PassRefPtr<AXValue> createRelatedNodeValue(const AXObject* axObject, String* name, AXValueType::Enum valueType)
+PassRefPtr<AXValue> createRelatedNodeListValue(const AXObject* axObject, String* name, AXValueType::Enum valueType)
 {
     RefPtr<AXValue> axValue = AXValue::create().setType(valueType);
     RefPtr<AXRelatedNode> relatedNode = relatedNodeForAXObject(axObject, name);
-    axValue->setRelatedNodeValue(relatedNode);
+    RefPtr<TypeBuilder::Array<AXRelatedNode>> relatedNodes = TypeBuilder::Array<AXRelatedNode>::create();
+    relatedNodes->addItem(relatedNode);
+    axValue->setRelatedNodes(relatedNodes);
     return axValue;
 }
 
@@ -163,7 +165,7 @@
             frontendRelatedNodes->addItem(frontendRelatedNode);
     }
     RefPtr<AXValue> axValue = AXValue::create().setType(valueType);
-    axValue->setRelatedNodeArrayValue(frontendRelatedNodes);
+    axValue->setRelatedNodes(frontendRelatedNodes);
     return axValue;
 }
 
@@ -176,7 +178,7 @@
             relatedNodes->addItem(relatedNode);
     }
     RefPtr<AXValue> axValue = AXValue::create().setType(valueType);
-    axValue->setRelatedNodeArrayValue(relatedNodes);
+    axValue->setRelatedNodes(relatedNodes);
     return axValue;
 }
 
diff --git a/third_party/WebKit/Source/modules/accessibility/InspectorTypeBuilderHelper.h b/third_party/WebKit/Source/modules/accessibility/InspectorTypeBuilderHelper.h
index e2876b3..143acb2 100644
--- a/third_party/WebKit/Source/modules/accessibility/InspectorTypeBuilderHelper.h
+++ b/third_party/WebKit/Source/modules/accessibility/InspectorTypeBuilderHelper.h
@@ -34,7 +34,7 @@
 PassRefPtr<AXValue> createValue(int value, AXValueType::Enum = AXValueType::Integer);
 PassRefPtr<AXValue> createValue(float value, AXValueType::Enum = AXValueType::Number);
 PassRefPtr<AXValue> createBooleanValue(bool value, AXValueType::Enum = AXValueType::Boolean);
-PassRefPtr<AXValue> createRelatedNodeValue(const AXObject*, String* name = nullptr, AXValueType::Enum = AXValueType::Idref);
+PassRefPtr<AXValue> createRelatedNodeListValue(const AXObject*, String* name = nullptr, AXValueType::Enum = AXValueType::Idref);
 PassRefPtr<AXValue> createRelatedNodeListValue(AXRelatedObjectVector&, AXValueType::Enum);
 PassRefPtr<AXValue> createRelatedNodeListValue(AXObject::AXObjectVector& axObjects, AXValueType::Enum = AXValueType::IdrefList);
 
diff --git a/third_party/WebKit/Source/modules/mediarecorder/MediaRecorder.cpp b/third_party/WebKit/Source/modules/mediarecorder/MediaRecorder.cpp
index bd0f537..d24c1b83 100644
--- a/third_party/WebKit/Source/modules/mediarecorder/MediaRecorder.cpp
+++ b/third_party/WebKit/Source/modules/mediarecorder/MediaRecorder.cpp
@@ -104,6 +104,7 @@
     m_state = State::Recording;
 
     m_recorderHandler->start(timeSlice);
+    scheduleDispatchEvent(Event::create(EventTypeNames::start));
 }
 
 void MediaRecorder::stop(ExceptionState& exceptionState)
@@ -144,6 +145,7 @@
     m_state = State::Recording;
 
     m_recorderHandler->resume();
+    scheduleDispatchEvent(Event::create(EventTypeNames::resume));
 }
 
 void MediaRecorder::requestData(ExceptionState& exceptionState)
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index 479e5d4..7a1ce07 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -155,7 +155,6 @@
 SlimmingPaintV2
 SlimmingPaintOffsetCaching implied_by=SlimmingPaintV2, implied_by=SlimmingPaintSynchronizedPainting
 SlimmingPaintStrictCullRectClipping
-SlimmingPaintSubsequenceCaching implied_by=SlimmingPaintV2
 SlimmingPaintSynchronizedPainting implied_by=SlimmingPaintV2
 SlimmingPaintUnderInvalidationChecking
 StackedCSSPropertyAnimations status=experimental
diff --git a/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp b/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp
index 86569bc..fc5f41d 100644
--- a/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp
@@ -66,16 +66,6 @@
 }
 
 void ContentLayerDelegate::paintContents(
-    SkCanvas* canvas, const WebRect& clip,
-    WebContentLayerClient::PaintingControlSetting paintingControl)
-{
-    TRACE_EVENT1("blink,benchmark", "ContentLayerDelegate::paintContents", "clip_rect", toTracedValue(clip));
-
-    // TODO(pdr): Remove this function.
-    ASSERT_NOT_REACHED();
-}
-
-void ContentLayerDelegate::paintContents(
     WebDisplayItemList* webDisplayItemList, const WebRect& clip,
     WebContentLayerClient::PaintingControlSetting paintingControl)
 {
@@ -103,7 +93,7 @@
     if (paintingControl == WebContentLayerClient::DisplayListPaintingDisabled
         || paintingControl == WebContentLayerClient::DisplayListConstructionDisabled)
         disabledMode = GraphicsContext::FullyDisabled;
-    GraphicsContext context(paintController, disabledMode);
+    GraphicsContext context(*paintController, disabledMode);
 
     m_painter->paint(context, clip);
 
diff --git a/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.h b/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.h
index 9d055181..387c42cb 100644
--- a/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.h
+++ b/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.h
@@ -58,7 +58,6 @@
     ~ContentLayerDelegate() override;
 
     // WebContentLayerClient implementation.
-    void paintContents(SkCanvas*, const WebRect& clip, WebContentLayerClient::PaintingControlSetting = PaintDefaultBehavior) override;
     void paintContents(WebDisplayItemList*, const WebRect& clip, WebContentLayerClient::PaintingControlSetting = PaintDefaultBehavior) override;
     size_t approximateUnsharedMemoryUsage() const override;
 
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
index 8a211e6..ae42a0b 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
@@ -50,7 +50,7 @@
 
 namespace blink {
 
-GraphicsContext::GraphicsContext(PaintController* paintController, DisabledMode disableContextOrPainting, SkMetaData* metaData)
+GraphicsContext::GraphicsContext(PaintController& paintController, DisabledMode disableContextOrPainting, SkMetaData* metaData)
     : m_canvas(nullptr)
     , m_originalCanvas(nullptr)
     , m_paintController(paintController)
@@ -66,9 +66,6 @@
     , m_printing(false)
     , m_hasMetaData(!!metaData)
 {
-    // TODO(chrishtr): switch the type of the parameter to PaintController&.
-    ASSERT(paintController);
-
     if (metaData)
         m_metaData = *metaData;
 
@@ -734,7 +731,7 @@
         return;
 
     if (font.drawText(m_canvas, runInfo, point, m_deviceScaleFactor, paint))
-        m_paintController->setTextPainted();
+        m_paintController.setTextPainted();
 }
 
 template<typename DrawTextFunc>
@@ -762,7 +759,7 @@
 
     drawTextPasses([&font, &runInfo, &point, this](const SkPaint& paint) {
         if (font.drawText(m_canvas, runInfo, point, m_deviceScaleFactor, paint))
-            m_paintController->setTextPainted();
+            m_paintController.setTextPainted();
     });
 }
 
@@ -783,7 +780,7 @@
 
     drawTextPasses([&font, &runInfo, &point, customFontNotReadyAction, this](const SkPaint& paint) {
         if (font.drawBidiText(m_canvas, runInfo, point, customFontNotReadyAction, m_deviceScaleFactor, paint))
-            m_paintController->setTextPainted();
+            m_paintController.setTextPainted();
     });
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.h b/third_party/WebKit/Source/platform/graphics/GraphicsContext.h
index 8491ed4..45980cc4 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.h
@@ -69,14 +69,15 @@
         FullyDisabled = 1 // Do absolutely minimal work to remove the cost of the context from performance tests.
     };
 
-    explicit GraphicsContext(PaintController*, DisabledMode = NothingDisabled, SkMetaData* = 0);
+    explicit GraphicsContext(PaintController&, DisabledMode = NothingDisabled, SkMetaData* = 0);
 
     ~GraphicsContext();
 
     SkCanvas* canvas() { return m_canvas; }
     const SkCanvas* canvas() const { return m_canvas; }
 
-    PaintController* paintController() { return m_paintController; }
+    // TODO(pdr): Update this to return a reference.
+    PaintController* paintController() { return &m_paintController; }
 
     bool contextDisabled() const { return m_disabledState; }
 
@@ -343,8 +344,7 @@
     // used when Slimming Paint is active.
     SkCanvas* m_originalCanvas;
 
-    // This being null indicates not to paint using the PaintController, and instead directly into the canvas.
-    PaintController* m_paintController;
+    PaintController& m_paintController;
 
     // Paint states stack. Enables local drawing state change with save()/restore() calls.
     // This state controls the appearance of drawn content.
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContextTest.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsContextTest.cpp
index 91d4805d..56f0517 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContextTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContextTest.cpp
@@ -70,7 +70,7 @@
     SkCanvas canvas(bitmap);
 
     OwnPtr<PaintController> paintController = PaintController::create();
-    GraphicsContext context(paintController.get());
+    GraphicsContext context(*paintController);
 
     Color opaque(1.0f, 0.0f, 0.0f, 1.0f);
     FloatRect bounds(0, 0, 100, 100);
@@ -103,7 +103,7 @@
     FloatRect bounds(0, 0, 100, 100);
 
     OwnPtr<PaintController> paintController = PaintController::create();
-    GraphicsContext context(paintController.get());
+    GraphicsContext context(*paintController);
     context.beginRecording(bounds);
 
     context.setShouldAntialias(false);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
index 3d5ab62..459aba9 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
@@ -21,7 +21,7 @@
 public:
     PaintControllerTest()
         : m_paintController(PaintController::create())
-        , m_originalSlimmingPaintSubsequenceCachingEnabled(RuntimeEnabledFeatures::slimmingPaintSubsequenceCachingEnabled())
+        , m_originalSlimmingPaintSynchronizedPaintingEnabled(RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled())
         , m_originalSlimmingPaintV2Enabled(RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { }
 
 protected:
@@ -30,12 +30,12 @@
 private:
     void TearDown() override
     {
-        RuntimeEnabledFeatures::setSlimmingPaintSubsequenceCachingEnabled(m_originalSlimmingPaintSubsequenceCachingEnabled);
+        RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(m_originalSlimmingPaintSynchronizedPaintingEnabled);
         RuntimeEnabledFeatures::setSlimmingPaintV2Enabled(m_originalSlimmingPaintV2Enabled);
     }
 
     OwnPtr<PaintController> m_paintController;
-    bool m_originalSlimmingPaintSubsequenceCachingEnabled;
+    bool m_originalSlimmingPaintSynchronizedPaintingEnabled;
     bool m_originalSlimmingPaintV2Enabled;
 };
 
@@ -105,7 +105,7 @@
 
 TEST_F(PaintControllerTest, NestedRecorders)
 {
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     TestDisplayItemClient client("client");
 
@@ -122,7 +122,7 @@
 {
     TestDisplayItemClient first("first");
     TestDisplayItemClient second("second");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     drawRect(context, first, backgroundDrawingType, FloatRect(100, 100, 300, 300));
     drawRect(context, second, backgroundDrawingType, FloatRect(100, 100, 200, 200));
@@ -149,7 +149,7 @@
     TestDisplayItemClient first("first");
     TestDisplayItemClient second("second");
     TestDisplayItemClient unaffected("unaffected");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     drawRect(context, first, backgroundDrawingType, FloatRect(100, 100, 100, 100));
     drawRect(context, second, backgroundDrawingType, FloatRect(100, 100, 50, 200));
@@ -178,7 +178,7 @@
     TestDisplayItemClient first("first");
     TestDisplayItemClient second("second");
     TestDisplayItemClient third("third");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     drawRect(context, first, backgroundDrawingType, FloatRect(100, 100, 100, 100));
     drawRect(context, second, backgroundDrawingType, FloatRect(100, 100, 50, 200));
@@ -204,7 +204,7 @@
     TestDisplayItemClient first("first");
     TestDisplayItemClient second("second");
     TestDisplayItemClient third("third");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     drawRect(context, first, backgroundDrawingType, FloatRect(100, 100, 100, 100));
     drawRect(context, second, backgroundDrawingType, FloatRect(100, 100, 50, 200));
@@ -244,7 +244,7 @@
 {
     TestDisplayItemClient first("first");
     TestDisplayItemClient second("second");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     drawRect(context, second, backgroundDrawingType, FloatRect(200, 200, 50, 50));
     drawRect(context, second, foregroundDrawingType, FloatRect(200, 200, 50, 50));
@@ -282,7 +282,7 @@
 {
     TestDisplayItemClient first("first");
     TestDisplayItemClient second("second");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     drawRect(context, first, backgroundDrawingType, FloatRect(100, 100, 150, 150));
     drawRect(context, first, foregroundDrawingType, FloatRect(100, 100, 150, 150));
@@ -321,7 +321,7 @@
 {
     TestDisplayItemClient first("first");
     TestDisplayItemClient second("second");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     {
         ClipRecorder clipRecorder(context, first, clipType, LayoutRect(1, 1, 2, 2));
@@ -364,7 +364,7 @@
 {
     TestDisplayItemClient first("first");
     TestDisplayItemClient second("second");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     drawRect(context, first, backgroundDrawingType, FloatRect(100, 100, 150, 150));
     drawRect(context, second, backgroundDrawingType, FloatRect(100, 100, 150, 150));
@@ -407,7 +407,7 @@
     TestDisplayItemClient content1("content1");
     TestDisplayItemClient container2("container2");
     TestDisplayItemClient content2("content2");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     drawRect(context, container1, backgroundDrawingType, FloatRect(100, 100, 100, 100));
     drawRect(context, content1, backgroundDrawingType, FloatRect(100, 100, 50, 200));
@@ -454,13 +454,13 @@
 
 TEST_F(PaintControllerTest, CachedSubsequenceSwapOrder)
 {
-    RuntimeEnabledFeatures::setSlimmingPaintSubsequenceCachingEnabled(true);
+    RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(true);
 
     TestDisplayItemClient container1("container1");
     TestDisplayItemClient content1("content1");
     TestDisplayItemClient container2("container2");
     TestDisplayItemClient content2("content2");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     {
         SubsequenceRecorder r(context, container1, subsequenceType);
@@ -522,7 +522,7 @@
 TEST_F(PaintControllerTest, OutOfOrderNoCrash)
 {
     TestDisplayItemClient client("client");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     const DisplayItem::Type type1 = DisplayItem::DrawingFirst;
     const DisplayItem::Type type2 = static_cast<DisplayItem::Type>(DisplayItem::DrawingFirst + 1);
@@ -546,13 +546,13 @@
 
 TEST_F(PaintControllerTest, CachedNestedSubsequenceUpdate)
 {
-    RuntimeEnabledFeatures::setSlimmingPaintSubsequenceCachingEnabled(true);
+    RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(true);
 
     TestDisplayItemClient container1("container1");
     TestDisplayItemClient content1("content1");
     TestDisplayItemClient container2("container2");
     TestDisplayItemClient content2("content2");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     {
         SubsequenceRecorder r(context, container1, subsequenceType);
@@ -643,7 +643,7 @@
 {
     TestDisplayItemClient multicol("multicol");
     TestDisplayItemClient content("content");
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
 
     FloatRect rect1(100, 100, 50, 50);
     FloatRect rect2(150, 100, 50, 50);
@@ -727,7 +727,7 @@
     TestDisplayItemClient second("second");
     TestDisplayItemClient third("third");
 
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
     drawRect(context, first, backgroundDrawingType, FloatRect(0, 0, 100, 100));
     {
         ClipPathRecorder clipRecorder(context, second, Path());
@@ -780,7 +780,7 @@
     RuntimeEnabledFeatures::setSlimmingPaintV2Enabled(true);
     TestDisplayItemClient client("test client");
 
-    GraphicsContext context(&paintController());
+    GraphicsContext context(paintController());
     drawRect(context, client, backgroundDrawingType, FloatRect(0, 0, 100, 100));
 
     paintController().commitNewDisplayItems();
diff --git a/third_party/WebKit/Source/platform/graphics/paint/SkPictureBuilder.h b/third_party/WebKit/Source/platform/graphics/paint/SkPictureBuilder.h
index 900a420..a9341ac 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/SkPictureBuilder.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/SkPictureBuilder.h
@@ -26,7 +26,7 @@
             disabledMode = GraphicsContext::FullyDisabled;
 
         m_paintController = PaintController::create();
-        m_context = adoptPtr(new GraphicsContext(m_paintController.get(), disabledMode, metaData));
+        m_context = adoptPtr(new GraphicsContext(*m_paintController, disabledMode, metaData));
 
         if (containingContext) {
             m_context->setDeviceScaleFactor(containingContext->deviceScaleFactor());
diff --git a/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.cpp b/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.cpp
index 6a18932..4942152 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.cpp
@@ -15,7 +15,7 @@
 
 bool SubsequenceRecorder::useCachedSubsequenceIfPossible(GraphicsContext& context, const DisplayItemClientWrapper& client, DisplayItem::Type type)
 {
-    if (!RuntimeEnabledFeatures::slimmingPaintSubsequenceCachingEnabled())
+    if (!RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled())
         return false;
 
     ASSERT(context.paintController());
@@ -44,7 +44,7 @@
     , m_beginSubsequenceIndex(0)
     , m_type(type)
 {
-    if (!RuntimeEnabledFeatures::slimmingPaintSubsequenceCachingEnabled())
+    if (!RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled())
         return;
 
     ASSERT(m_paintController);
@@ -57,7 +57,7 @@
 
 SubsequenceRecorder::~SubsequenceRecorder()
 {
-    if (!RuntimeEnabledFeatures::slimmingPaintSubsequenceCachingEnabled())
+    if (!RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled())
         return;
 
     if (m_paintController->displayItemConstructionIsDisabled())
@@ -78,7 +78,7 @@
 
 void SubsequenceRecorder::setUncacheable()
 {
-    if (!RuntimeEnabledFeatures::slimmingPaintSubsequenceCachingEnabled())
+    if (!RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled())
         return;
 
     if (m_paintController->displayItemConstructionIsDisabled())
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
index 5577228..b53773a 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -662,13 +662,13 @@
     return m_lastSetMouseCursorForTesting;
 }
 
-void ChromeClientImpl::setCursor(const Cursor& cursor)
+void ChromeClientImpl::setCursor(const Cursor& cursor, LocalFrame* localRoot)
 {
     m_lastSetMouseCursorForTesting = cursor;
-    setCursor(WebCursorInfo(cursor));
+    setCursor(WebCursorInfo(cursor), localRoot);
 }
 
-void ChromeClientImpl::setCursor(const WebCursorInfo& cursor)
+void ChromeClientImpl::setCursor(const WebCursorInfo& cursor, LocalFrame* localRoot)
 {
     if (m_cursorOverridden)
         return;
@@ -679,13 +679,25 @@
     if (m_webView->hasOpenedPopup())
         return;
 #endif
-    if (m_webView->client())
+    if (!m_webView->client())
+        return;
+    // TODO(kenrb, dcheng): For top-level frames we still use the WebView as
+    // a WebWidget. This special case will be removed when top-level frames
+    // get WebFrameWidgets.
+    if (localRoot->isMainFrame()) {
         m_webView->client()->didChangeCursor(cursor);
+    } else {
+        WebLocalFrameImpl* webFrame = WebLocalFrameImpl::fromFrame(localRoot);
+        ASSERT(webFrame);
+        ASSERT(webFrame->frameWidget());
+        if (toWebFrameWidgetImpl(webFrame->frameWidget())->client())
+            toWebFrameWidgetImpl(webFrame->frameWidget())->client()->didChangeCursor(cursor);
+    }
 }
 
 void ChromeClientImpl::setCursorForPlugin(const WebCursorInfo& cursor)
 {
-    setCursor(cursor);
+    setCursor(cursor, m_webView->page()->deprecatedLocalMainFrame());
 }
 
 void ChromeClientImpl::setCursorOverridden(bool overridden)
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.h b/third_party/WebKit/Source/web/ChromeClientImpl.h
index 46054cdd..bed75e3 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.h
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.h
@@ -110,7 +110,7 @@
     PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) override;
     void openFileChooser(LocalFrame*, PassRefPtr<FileChooser>) override;
     void enumerateChosenDirectory(FileChooser*) override;
-    void setCursor(const Cursor&) override;
+    void setCursor(const Cursor&, LocalFrame* localRoot) override;
     Cursor lastSetCursorForTesting() const override;
     void needTouchEvents(bool needTouchEvents) override;
     void setTouchAction(TouchAction) override;
@@ -184,7 +184,7 @@
     void unregisterPopupOpeningObserver(PopupOpeningObserver*) override;
 
     void notifyPopupOpeningObservers() const;
-    void setCursor(const WebCursorInfo&);
+    void setCursor(const WebCursorInfo&, LocalFrame* localRoot);
 
     WebViewImpl* m_webView; // Weak pointer.
     WindowFeatures m_windowFeatures;
diff --git a/third_party/WebKit/Source/web/InspectorOverlay.cpp b/third_party/WebKit/Source/web/InspectorOverlay.cpp
index 3709007..b39e27b 100644
--- a/third_party/WebKit/Source/web/InspectorOverlay.cpp
+++ b/third_party/WebKit/Source/web/InspectorOverlay.cpp
@@ -138,10 +138,10 @@
         EmptyChromeClient::trace(visitor);
     }
 
-    void setCursor(const Cursor& cursor) override
+    void setCursor(const Cursor& cursor, LocalFrame* localRoot) override
     {
         toChromeClientImpl(m_client)->setCursorOverridden(false);
-        toChromeClientImpl(m_client)->setCursor(cursor);
+        toChromeClientImpl(m_client)->setCursor(cursor, localRoot);
         bool overrideCursor = m_overlay->m_layoutEditor;
         toChromeClientImpl(m_client)->setCursorOverridden(overrideCursor);
     }
@@ -633,7 +633,7 @@
         highlightNode(m_hoveredNodeForInspectMode.get(), *m_inspectModeHighlightConfig, false);
 
     toChromeClientImpl(m_webViewImpl->page()->chromeClient()).setCursorOverridden(false);
-    toChromeClientImpl(m_webViewImpl->page()->chromeClient()).setCursor(pointerCursor());
+    toChromeClientImpl(m_webViewImpl->page()->chromeClient()).setCursor(pointerCursor(), overlayMainFrame());
 }
 
 void InspectorOverlay::profilingStarted()
diff --git a/third_party/WebKit/Source/web/LinkHighlightImpl.cpp b/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
index b7cb039..98232f4 100644
--- a/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
+++ b/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
@@ -257,18 +257,6 @@
     return pathHasChanged;
 }
 
-void LinkHighlightImpl::paintContents(WebCanvas* canvas, const WebRect&, WebContentLayerClient::PaintingControlSetting paintingControl)
-{
-    if (!m_node || !m_node->layoutObject())
-        return;
-
-    SkPaint paint;
-    paint.setStyle(SkPaint::kFill_Style);
-    paint.setFlags(SkPaint::kAntiAlias_Flag);
-    paint.setColor(m_node->layoutObject()->style()->tapHighlightColor().rgb());
-    canvas->drawPath(m_path.skPath(), paint);
-}
-
 void LinkHighlightImpl::paintContents(WebDisplayItemList* webDisplayItemList, const WebRect& webClipRect, WebContentLayerClient::PaintingControlSetting paintingControl)
 {
     if (!m_node || !m_node->layoutObject())
@@ -277,7 +265,13 @@
     SkPictureRecorder recorder;
     SkCanvas* canvas = recorder.beginRecording(webClipRect.width, webClipRect.height);
     canvas->translate(-webClipRect.x, -webClipRect.y);
-    paintContents(canvas, webClipRect, paintingControl);
+
+    SkPaint paint;
+    paint.setStyle(SkPaint::kFill_Style);
+    paint.setFlags(SkPaint::kAntiAlias_Flag);
+    paint.setColor(m_node->layoutObject()->style()->tapHighlightColor().rgb());
+    canvas->drawPath(m_path.skPath(), paint);
+
     RefPtr<const SkPicture> picture = adoptRef(recorder.endRecording());
     webDisplayItemList->appendDrawingItem(picture.get());
 }
diff --git a/third_party/WebKit/Source/web/LinkHighlightImpl.h b/third_party/WebKit/Source/web/LinkHighlightImpl.h
index fe34dae..64235b7 100644
--- a/third_party/WebKit/Source/web/LinkHighlightImpl.h
+++ b/third_party/WebKit/Source/web/LinkHighlightImpl.h
@@ -60,7 +60,6 @@
     void updateGeometry();
 
     // WebContentLayerClient implementation.
-    void paintContents(WebCanvas*, const WebRect& clipRect, WebContentLayerClient::PaintingControlSetting) override;
     void paintContents(WebDisplayItemList*, const WebRect& clipRect, WebContentLayerClient::PaintingControlSetting) override;
 
     // WebCompositorAnimationDelegate implementation.
diff --git a/third_party/WebKit/Source/web/PageOverlayTest.cpp b/third_party/WebKit/Source/web/PageOverlayTest.cpp
index a64de62c..0a19a8d0 100644
--- a/third_party/WebKit/Source/web/PageOverlayTest.cpp
+++ b/third_party/WebKit/Source/web/PageOverlayTest.cpp
@@ -152,12 +152,14 @@
 
     // Paint the layer with a null canvas to get a display list, and then
     // replay that onto the mock canvas for examination.
-    GraphicsContext graphicsContext(graphicsLayer->paintController());
+    PaintController* paintController = graphicsLayer->paintController();
+    ASSERT(paintController);
+    GraphicsContext graphicsContext(*paintController);
     graphicsLayer->paint(graphicsContext, rect);
 
     graphicsContext.beginRecording(IntRect(rect));
-    graphicsLayer->paintController()->commitNewDisplayItems();
-    graphicsLayer->paintController()->paintArtifact().replay(graphicsContext);
+    paintController->commitNewDisplayItems();
+    paintController->paintArtifact().replay(graphicsContext);
     graphicsContext.endRecording()->playback(&canvas);
 }
 
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
index 1f2c807..7234d0b 100644
--- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
+++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
@@ -469,7 +469,7 @@
     m_agents.append(InspectorInputAgent::create(m_inspectedFrames.get()));
 
     v8::Isolate* isolate = V8PerIsolateData::mainThreadIsolate();
-    m_agents.append(InspectorProfilerAgent::create(isolate, injectedScriptManager, m_overlay.get()));
+    m_agents.append(InspectorProfilerAgent::create(isolate, m_overlay.get()));
 
     m_agents.append(InspectorHeapProfilerAgent::create(isolate, injectedScriptManager));
 
diff --git a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
index 6f14730..208acec 100644
--- a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
@@ -157,7 +157,7 @@
         return IntSize(0, 0);
     }
 
-    void setCursor(const Cursor& cursor) override
+    void setCursor(const Cursor& cursor, LocalFrame* localRoot) override
     {
         if (m_popup->m_webView->client())
             m_popup->m_webView->client()->didChangeCursor(WebCursorInfo(cursor));
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
index 5715802c..bd2e7d0e 100644
--- a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
@@ -724,8 +724,10 @@
     for (size_t i = 0; i < m_pluginLoadObservers.size(); ++i)
         m_pluginLoadObservers[i]->clearPluginContainer();
 
-    if (m_webPlugin)
+    if (m_webPlugin) {
+        RELEASE_ASSERT(!m_webPlugin->container() || m_webPlugin->container() == this);
         m_webPlugin->destroy();
+    }
     m_webPlugin = nullptr;
 
     if (m_webLayer) {
diff --git a/third_party/WebKit/Tools/Scripts/run-blink-wptserve b/third_party/WebKit/Tools/Scripts/run-blink-wptserve
new file mode 100755
index 0000000..f94e7c85
--- /dev/null
+++ b/third_party/WebKit/Tools/Scripts/run-blink-wptserve
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+# 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.
+
+# Runs an instance of wptserve to allow manual testing of the imported Web
+# Platform Tests. The main HTTP server is run on 8001, while the main HTTPS
+# server is run on 8444.
+
+import webkitpy.common.version_check
+
+from webkitpy.layout_tests.servers import cli_wrapper
+from webkitpy.layout_tests.servers import wptserve
+
+cli_wrapper.main(wptserve.WPTServe)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
index 1f962942..619585f 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
@@ -474,6 +474,8 @@
         self._port.clobber_old_port_specific_results()
 
     def _tests_to_retry(self, run_results):
+        # TODO(ojan): This should also check that result.type != test_expectations.MISSING since retrying missing expectations is silly.
+        # But that's a bit tricky since we only consider the last retry attempt for the count of unexpected regressions.
         return [result.test_name for result in run_results.unexpected_results_by_name.values() if result.type != test_expectations.PASS]
 
     def _write_json_files(self, summarized_full_results, summarized_failing_results, initial_results, running_all_tests):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
index 086891b..4c2f2bc 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
@@ -128,9 +128,15 @@
             default=False, help="Save generated results as new baselines "
                  "into the *most-specific-platform* directory, overwriting whatever's "
                  "already there. Equivalent to --reset-results --add-platform-exceptions"),
-        optparse.make_option("--no-new-test-results", action="store_false",
-            dest="new_test_results", default=True,
-            help="Don't create new baselines when no expected results exist"),
+
+        # TODO(ojan): Remove once bots stop using it.
+        optparse.make_option("--no-new-test-results",
+            help="This doesn't do anything. TODO(ojan): Remove once bots stop using it."),
+
+        optparse.make_option("--new-test-results", action="store_true",
+            default=False,
+            help="Create new baselines when no expected results exist"),
+
         optparse.make_option("--no-show-results", action="store_false",
             default=True, dest="show_results",
             help="Don't launch a browser with results after the tests "
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
index 7b1bc85..9814900 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
@@ -62,8 +62,8 @@
     args = []
     if not '--platform' in extra_args:
         args.extend(['--platform', 'test'])
-    if not new_results:
-        args.append('--no-new-test-results')
+    if new_results:
+        args.append('--new-test-results')
 
     if not '--child-processes' in extra_args:
         args.extend(['--child-processes', 1])
diff --git a/third_party/WebKit/public/platform/WebContentLayerClient.h b/third_party/WebKit/public/platform/WebContentLayerClient.h
index abf25d7..7e28aee 100644
--- a/third_party/WebKit/public/platform/WebContentLayerClient.h
+++ b/third_party/WebKit/public/platform/WebContentLayerClient.h
@@ -26,7 +26,6 @@
 #ifndef WebContentLayerClient_h
 #define WebContentLayerClient_h
 
-#include "WebCanvas.h"
 #include "WebCommon.h"
 
 namespace blink {
@@ -44,13 +43,6 @@
     };
 
     // Paints the content area for the layer, typically dirty rects submitted
-    // through WebContentLayer::setNeedsDisplay, submitting drawing commands
-    // through the WebCanvas.
-    // The canvas is already clipped to the |clip| rect.
-    // The |PaintingControlSetting| enum controls painting to isolate different components in performance tests.
-    virtual void paintContents(WebCanvas*, const WebRect& clip, PaintingControlSetting = PaintDefaultBehavior) = 0;
-
-    // Paints the content area for the layer, typically dirty rects submitted
     // through WebContentLayer::setNeedsDisplayInRect, submitting drawing commands
     // to populate the WebDisplayItemList.
     // The |clip| rect defines the region of interest. The resulting WebDisplayItemList should contain
diff --git a/third_party/WebKit/public/web/WebInputEvent.h b/third_party/WebKit/public/web/WebInputEvent.h
index 4751e088..53ca6a160 100644
--- a/third_party/WebKit/public/web/WebInputEvent.h
+++ b/third_party/WebKit/public/web/WebInputEvent.h
@@ -283,6 +283,11 @@
     // easier to leave it always false than ifdef.
     bool isSystemKey;
 
+    // Whether the event forms part of a browser-handled keyboard shortcut.
+    // This can be used to conditionally suppress Char events after a
+    // shortcut-triggering RawKeyDown goes unhandled.
+    bool isBrowserShortcut;
+
     // |text| is the text generated by this keystroke.  |unmodifiedText| is
     // |text|, but unmodified by an concurrently-held modifiers (except
     // shift).  This is useful for working out shortcut keys.  Linux and
@@ -300,6 +305,7 @@
         , windowsKeyCode(0)
         , nativeKeyCode(0)
         , isSystemKey(false)
+        , isBrowserShortcut(false)
     {
         memset(&text, 0, sizeof(text));
         memset(&unmodifiedText, 0, sizeof(unmodifiedText));
diff --git a/third_party/WebKit/public/web/WebPlugin.h b/third_party/WebKit/public/web/WebPlugin.h
index 20aaf78..58888f6c1 100644
--- a/third_party/WebKit/public/web/WebPlugin.h
+++ b/third_party/WebKit/public/web/WebPlugin.h
@@ -61,14 +61,21 @@
 
 class WebPlugin {
 public:
+    // Perform any initialization work given the container this plugin will use to
+    // communicate with renderer code. Plugins that return false here must
+    // subsequently return nullptr for the container() method.
     virtual bool initialize(WebPluginContainer*) = 0;
+
+    // Plugins must arrange for themselves to be deleted sometime during or after this
+    // method is called.
     virtual void destroy() = 0;
 
-    virtual WebPluginContainer* container() const { return 0; }
+    // Must return null container when the initialize() method returns false.
+    virtual WebPluginContainer* container() const { return nullptr; }
     virtual void containerDidDetachFromParent() { }
 
-    virtual NPObject* scriptableObject() { return 0; }
-    virtual struct _NPP* pluginNPP() { return 0; }
+    virtual NPObject* scriptableObject() { return nullptr; }
+    virtual struct _NPP* pluginNPP() { return nullptr; }
 
     // The same as scriptableObject() but allows to expose scriptable interface
     // through plain v8 object instead of NPObject.
diff --git a/third_party/binutils/download.py b/third_party/binutils/download.py
index 6a760df..17c7868 100755
--- a/third_party/binutils/download.py
+++ b/third_party/binutils/download.py
@@ -9,6 +9,7 @@
 TODO(mithro): Replace with generic download_and_extract tool.
 """
 
+import argparse
 import os
 import platform
 import re
@@ -98,10 +99,20 @@
 
 
 def main(args):
+  parser = argparse.ArgumentParser(description=__doc__)
+  parser.add_argument('--ignore-if-arch', metavar='ARCH',
+                      action='append', default=[],
+                      help='Do nothing on host architecture ARCH')
+
+  options = parser.parse_args(args)
+
   if not sys.platform.startswith('linux'):
     return 0
 
   arch = GetArch()
+  if arch in options.ignore_if_arch:
+    return 0
+
   if arch == 'x64':
     return FetchAndExtract(arch)
   if arch == 'ia32':
@@ -110,9 +121,10 @@
       return ret
     # Fetch the x64 toolchain as well for official bots with 64-bit kernels.
     return FetchAndExtract('x64')
+
   print "Host architecture %s is not supported." % arch
   return 1
 
 
 if __name__ == '__main__':
-  sys.exit(main(sys.argv))
+  sys.exit(main(sys.argv[1:]))
diff --git a/third_party/boringssl/boringssl.gypi b/third_party/boringssl/boringssl.gypi
index 2f98c90c..1c6d010 100644
--- a/third_party/boringssl/boringssl.gypi
+++ b/third_party/boringssl/boringssl.gypi
@@ -34,7 +34,6 @@
       'src/ssl/ssl_rsa.c',
       'src/ssl/ssl_session.c',
       'src/ssl/ssl_stat.c',
-      'src/ssl/ssl_txt.c',
       'src/ssl/t1_enc.c',
       'src/ssl/t1_lib.c',
       'src/ssl/tls_record.c',
@@ -152,6 +151,7 @@
       'src/crypto/ec/ec_key.c',
       'src/crypto/ec/ec_montgomery.c',
       'src/crypto/ec/oct.c',
+      'src/crypto/ec/p224-64.c',
       'src/crypto/ec/p256-64.c',
       'src/crypto/ec/simple.c',
       'src/crypto/ec/util-64.c',
diff --git a/third_party/closure_compiler/compiler_test.py b/third_party/closure_compiler/compiler_test.py
index 361d88c5..36cf163 100755
--- a/third_party/closure_compiler/compiler_test.py
+++ b/third_party/closure_compiler/compiler_test.py
@@ -56,8 +56,9 @@
                                                closure_args=args)
     return found_errors, stderr, out_file, out_map
 
-  def _runCheckerTestExpectError(self, source_code, expected_error):
-    _, stderr, out_file, out_map = self._runChecker(source_code)
+  def _runCheckerTestExpectError(self, source_code, expected_error,
+                                 closure_args=None):
+    _, stderr, out_file, out_map = self._runChecker(source_code, closure_args)
 
     self.assertTrue(expected_error in stderr,
         msg="Expected chunk: \n%s\n\nOutput:\n%s\n" % (
@@ -342,6 +343,31 @@
         "cr.exportPath();",
         "ERROR - cr.exportPath() should have at least 1 argument: path name")
 
+  def testMissingReturnAssertNotReached(self):
+    template = self._ASSERT_DEFINITION + """
+/** @enum {number} */
+var Enum = {FOO: 1, BAR: 2};
+
+/**
+ * @param {Enum} e
+ * @return {number}
+ */
+function enumToVal(e) {
+  switch (e) {
+    case Enum.FOO:
+      return 1;
+    case Enum.BAR:
+      return 2;
+  }
+  %s
+}
+"""
+    args = ['warning_level=VERBOSE']
+    self._runCheckerTestExpectError(template % '', 'Missing return',
+                                    closure_args=args)
+    self._runCheckerTestExpectSuccess(template % 'assertNotReached();',
+                                      closure_args=args)
+
 
 if __name__ == "__main__":
   unittest.main()
diff --git a/third_party/closure_compiler/externs/developer_private.js b/third_party/closure_compiler/externs/developer_private.js
index 8fe54fba3..9c6ded7 100644
--- a/third_party/closure_compiler/externs/developer_private.js
+++ b/third_party/closure_compiler/externs/developer_private.js
@@ -2,6 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// This file was generated by:
+//   tools/json_schema_compiler/compiler.py.
+// NOTE: The format of types has changed. 'FooType' is now
+//   'chrome.developerPrivate.FooType'.
+// Please run the closure compiler before committing changes.
+// See https://code.google.com/p/chromium/wiki/ClosureCompilation.
+
 /** @fileoverview Externs generated from namespace: developerPrivate */
 
 /**
@@ -31,7 +38,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-ItemInspectView
  */
-var ItemInspectView;
+chrome.developerPrivate.ItemInspectView;
 
 /**
  * @typedef {{
@@ -42,7 +49,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-InspectOptions
  */
-var InspectOptions;
+chrome.developerPrivate.InspectOptions;
 
 /**
  * @typedef {{
@@ -50,7 +57,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-InstallWarning
  */
-var InstallWarning;
+chrome.developerPrivate.InstallWarning;
 
 /**
  * @enum {string}
@@ -137,7 +144,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-AccessModifier
  */
-var AccessModifier;
+chrome.developerPrivate.AccessModifier;
 
 /**
  * @typedef {{
@@ -148,7 +155,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-StackFrame
  */
-var StackFrame;
+chrome.developerPrivate.StackFrame;
 
 /**
  * @typedef {{
@@ -163,7 +170,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-ManifestError
  */
-var ManifestError;
+chrome.developerPrivate.ManifestError;
 
 /**
  * @typedef {{
@@ -179,11 +186,11 @@
  *   renderViewId: number,
  *   renderProcessId: number,
  *   canInspect: boolean,
- *   stackTrace: !Array<StackFrame>
+ *   stackTrace: !Array<!chrome.developerPrivate.StackFrame>
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-RuntimeError
  */
-var RuntimeError;
+chrome.developerPrivate.RuntimeError;
 
 /**
  * @typedef {{
@@ -193,7 +200,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-DisableReasons
  */
-var DisableReasons;
+chrome.developerPrivate.DisableReasons;
 
 /**
  * @typedef {{
@@ -202,7 +209,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-OptionsPage
  */
-var OptionsPage;
+chrome.developerPrivate.OptionsPage;
 
 /**
  * @typedef {{
@@ -211,7 +218,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-HomePage
  */
-var HomePage;
+chrome.developerPrivate.HomePage;
 
 /**
  * @typedef {{
@@ -224,10 +231,11 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-ExtensionView
  */
-var ExtensionView;
+chrome.developerPrivate.ExtensionView;
 
 /**
  * @enum {string}
+ * @see https://developer.chrome.com/extensions/developerPrivate#type-ControllerType
  */
 chrome.developerPrivate.ControllerType = {
   POLICY: 'POLICY',
@@ -240,8 +248,9 @@
  *   type: !chrome.developerPrivate.ControllerType,
  *   text: string
  * }}
+ * @see https://developer.chrome.com/extensions/developerPrivate#type-ControlledInfo
  */
-var ControlledInfo;
+chrome.developerPrivate.ControlledInfo;
 
 /**
  * @typedef {{
@@ -254,47 +263,47 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-Command
  */
-var Command;
+chrome.developerPrivate.Command;
 
 /**
  * @typedef {{
  *   actionButtonHidden: boolean,
  *   blacklistText: (string|undefined),
- *   commands: !Array<Command>,
- *   controlledInfo: (ControlledInfo|undefined),
+ *   commands: !Array<!chrome.developerPrivate.Command>,
+ *   controlledInfo: (!chrome.developerPrivate.ControlledInfo|undefined),
  *   dependentExtensions: !Array<string>,
  *   description: string,
- *   disableReasons: DisableReasons,
- *   errorCollection: AccessModifier,
- *   fileAccess: AccessModifier,
- *   homePage: HomePage,
+ *   disableReasons: !chrome.developerPrivate.DisableReasons,
+ *   errorCollection: !chrome.developerPrivate.AccessModifier,
+ *   fileAccess: !chrome.developerPrivate.AccessModifier,
+ *   homePage: !chrome.developerPrivate.HomePage,
  *   iconUrl: string,
  *   id: string,
- *   incognitoAccess: AccessModifier,
+ *   incognitoAccess: !chrome.developerPrivate.AccessModifier,
  *   installWarnings: !Array<string>,
  *   launchUrl: (string|undefined),
  *   location: !chrome.developerPrivate.Location,
  *   locationText: (string|undefined),
- *   manifestErrors: !Array<ManifestError>,
+ *   manifestErrors: !Array<!chrome.developerPrivate.ManifestError>,
  *   mustRemainInstalled: boolean,
  *   name: string,
  *   offlineEnabled: boolean,
- *   optionsPage: (OptionsPage|undefined),
+ *   optionsPage: (!chrome.developerPrivate.OptionsPage|undefined),
  *   path: (string|undefined),
  *   prettifiedPath: (string|undefined),
- *   runOnAllUrls: AccessModifier,
- *   runtimeErrors: !Array<RuntimeError>,
+ *   runOnAllUrls: !chrome.developerPrivate.AccessModifier,
+ *   runtimeErrors: !Array<!chrome.developerPrivate.RuntimeError>,
  *   runtimeWarnings: !Array<string>,
  *   state: !chrome.developerPrivate.ExtensionState,
  *   type: !chrome.developerPrivate.ExtensionType,
  *   updateUrl: string,
  *   userMayModify: boolean,
  *   version: string,
- *   views: !Array<ExtensionView>
+ *   views: !Array<!chrome.developerPrivate.ExtensionView>
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-ExtensionInfo
  */
-var ExtensionInfo;
+chrome.developerPrivate.ExtensionInfo;
 
 /**
  * @typedef {{
@@ -306,7 +315,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-ProfileInfo
  */
-var ProfileInfo;
+chrome.developerPrivate.ProfileInfo;
 
 /**
  * @typedef {{
@@ -332,15 +341,15 @@
  *   app_launch_url: (string|undefined),
  *   homepage_url: (string|undefined),
  *   update_url: (string|undefined),
- *   install_warnings: !Array<InstallWarning>,
+ *   install_warnings: !Array<!chrome.developerPrivate.InstallWarning>,
  *   manifest_errors: !Array<*>,
  *   runtime_errors: !Array<*>,
  *   offline_enabled: boolean,
- *   views: !Array<ItemInspectView>
+ *   views: !Array<!chrome.developerPrivate.ItemInspectView>
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-ItemInfo
  */
-var ItemInfo;
+chrome.developerPrivate.ItemInfo;
 
 /**
  * @typedef {{
@@ -349,7 +358,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-GetExtensionsInfoOptions
  */
-var GetExtensionsInfoOptions;
+chrome.developerPrivate.GetExtensionsInfoOptions;
 
 /**
  * @typedef {{
@@ -362,7 +371,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-ExtensionConfigurationUpdate
  */
-var ExtensionConfigurationUpdate;
+chrome.developerPrivate.ExtensionConfigurationUpdate;
 
 /**
  * @typedef {{
@@ -370,7 +379,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-ProfileConfigurationUpdate
  */
-var ProfileConfigurationUpdate;
+chrome.developerPrivate.ProfileConfigurationUpdate;
 
 /**
  * @typedef {{
@@ -381,7 +390,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-ExtensionCommandUpdate
  */
-var ExtensionCommandUpdate;
+chrome.developerPrivate.ExtensionCommandUpdate;
 
 /**
  * @typedef {{
@@ -389,7 +398,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-ReloadOptions
  */
-var ReloadOptions;
+chrome.developerPrivate.ReloadOptions;
 
 /**
  * @typedef {{
@@ -397,7 +406,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-LoadUnpackedOptions
  */
-var LoadUnpackedOptions;
+chrome.developerPrivate.LoadUnpackedOptions;
 
 /**
  * @enum {string}
@@ -454,7 +463,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-PackDirectoryResponse
  */
-var PackDirectoryResponse;
+chrome.developerPrivate.PackDirectoryResponse;
 
 /**
  * @typedef {{
@@ -462,17 +471,17 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-ProjectInfo
  */
-var ProjectInfo;
+chrome.developerPrivate.ProjectInfo;
 
 /**
  * @typedef {{
  *   event_type: !chrome.developerPrivate.EventType,
  *   item_id: string,
- *   extensionInfo: (ExtensionInfo|undefined)
+ *   extensionInfo: (!chrome.developerPrivate.ExtensionInfo|undefined)
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-EventData
  */
-var EventData;
+chrome.developerPrivate.EventData;
 
 /**
  * @typedef {{
@@ -485,7 +494,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-RequestFileSourceProperties
  */
-var RequestFileSourceProperties;
+chrome.developerPrivate.RequestFileSourceProperties;
 
 /**
  * @typedef {{
@@ -497,7 +506,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-RequestFileSourceResponse
  */
-var RequestFileSourceResponse;
+chrome.developerPrivate.RequestFileSourceResponse;
 
 /**
  * @typedef {{
@@ -511,7 +520,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-OpenDevToolsProperties
  */
-var OpenDevToolsProperties;
+chrome.developerPrivate.OpenDevToolsProperties;
 
 /**
  * @typedef {{
@@ -521,7 +530,7 @@
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-DeleteExtensionErrorsProperties
  */
-var DeleteExtensionErrorsProperties;
+chrome.developerPrivate.DeleteExtensionErrorsProperties;
 
 /**
  * Runs auto update for extensions and apps immediately.
@@ -533,10 +542,10 @@
 
 /**
  * Returns information of all the extensions and apps installed.
- * @param {GetExtensionsInfoOptions=} options Options to restrict the items
- *     returned.
- * @param {function(!Array<ExtensionInfo>):void=} callback Called with
- *     extensions info.
+ * @param {!chrome.developerPrivate.GetExtensionsInfoOptions=} options Options
+ *     to restrict the items returned.
+ * @param {function(!Array<!chrome.developerPrivate.ExtensionInfo>):void=} callback Called with extensions
+ *     info.
  * @see https://developer.chrome.com/extensions/developerPrivate#method-getExtensionsInfo
  */
 chrome.developerPrivate.getExtensionsInfo = function(options, callback) {};
@@ -544,7 +553,8 @@
 /**
  * Returns information of a particular extension.
  * @param {string} id The id of the extension.
- * @param {function(ExtensionInfo):void=} callback Called with the result.
+ * @param {function(!chrome.developerPrivate.ExtensionInfo):void=} callback
+ *     Called with the result.
  * @see https://developer.chrome.com/extensions/developerPrivate#method-getExtensionInfo
  */
 chrome.developerPrivate.getExtensionInfo = function(id, callback) {};
@@ -553,7 +563,8 @@
  * Returns information of all the extensions and apps installed.
  * @param {boolean} includeDisabled include disabled items.
  * @param {boolean} includeTerminated include terminated items.
- * @param {function(!Array<ItemInfo>):void} callback Called with items info.
+ * @param {function(!Array<!chrome.developerPrivate.ItemInfo>):void} callback
+ *     Called with items info.
  * @deprecated Use getExtensionsInfo
  * @see https://developer.chrome.com/extensions/developerPrivate#method-getItemsInfo
  */
@@ -561,16 +572,16 @@
 
 /**
  * Returns the current profile's configuration.
- * @param {function(ProfileInfo):void} callback
+ * @param {function(!chrome.developerPrivate.ProfileInfo):void} callback
  * @see https://developer.chrome.com/extensions/developerPrivate#method-getProfileConfiguration
  */
 chrome.developerPrivate.getProfileConfiguration = function(callback) {};
 
 /**
  * Updates the active profile.
- * @param {ProfileConfigurationUpdate} update The parameters for updating the
- *     profile's configuration.  Any     properties omitted from |update| will
- *     not be changed.
+ * @param {!chrome.developerPrivate.ProfileConfigurationUpdate} update The
+ *     parameters for updating the profile's configuration.  Any     properties
+ *     omitted from |update| will not be changed.
  * @param {function():void=} callback
  * @see https://developer.chrome.com/extensions/developerPrivate#method-updateProfileConfiguration
  */
@@ -587,7 +598,8 @@
 /**
  * Reloads a given extension.
  * @param {string} extensionId The id of the extension to reload.
- * @param {ReloadOptions=} options Additional configuration parameters.
+ * @param {!chrome.developerPrivate.ReloadOptions=} options Additional
+ *     configuration parameters.
  * @param {function():void=} callback
  * @see https://developer.chrome.com/extensions/developerPrivate#method-reload
  */
@@ -595,9 +607,9 @@
 
 /**
  * Modifies an extension's current configuration.
- * @param {ExtensionConfigurationUpdate} update The parameters for updating the
- *     extension's configuration.     Any properties omitted from |update| will
- *     not be changed.
+ * @param {!chrome.developerPrivate.ExtensionConfigurationUpdate} update The
+ *     parameters for updating the extension's configuration.     Any properties
+ *     omitted from |update| will not be changed.
  * @param {function():void=} callback
  * @see https://developer.chrome.com/extensions/developerPrivate#method-updateExtensionConfiguration
  */
@@ -605,7 +617,8 @@
 
 /**
  * Loads a user-selected unpacked item.
- * @param {LoadUnpackedOptions=} options Additional configuration parameters.
+ * @param {!chrome.developerPrivate.LoadUnpackedOptions=} options Additional
+ *     configuration parameters.
  * @param {function():void=} callback
  * @see https://developer.chrome.com/extensions/developerPrivate#method-loadUnpacked
  */
@@ -636,8 +649,8 @@
  * @param {string} path
  * @param {string=} privateKeyPath The path of the private key, if one is given.
  * @param {number=} flags Special flags to apply to the loading process, if any.
- * @param {function(PackDirectoryResponse):void=} callback called with the
- *     success result string.
+ * @param {function(!chrome.developerPrivate.PackDirectoryResponse):void=} callback called with the success result
+ *     string.
  * @see https://developer.chrome.com/extensions/developerPrivate#method-packDirectory
  */
 chrome.developerPrivate.packDirectory = function(path, privateKeyPath, flags, callback) {};
@@ -652,15 +665,15 @@
 /**
  * Reads and returns the contents of a file related to an extension which caused
  * an error.
- * @param {RequestFileSourceProperties} properties
- * @param {function(RequestFileSourceResponse):void} callback
+ * @param {!chrome.developerPrivate.RequestFileSourceProperties} properties
+ * @param {function(!chrome.developerPrivate.RequestFileSourceResponse):void} callback
  * @see https://developer.chrome.com/extensions/developerPrivate#method-requestFileSource
  */
 chrome.developerPrivate.requestFileSource = function(properties, callback) {};
 
 /**
  * Open the developer tools to focus on a particular error.
- * @param {OpenDevToolsProperties} properties
+ * @param {!chrome.developerPrivate.OpenDevToolsProperties} properties
  * @param {function():void=} callback
  * @see https://developer.chrome.com/extensions/developerPrivate#method-openDevTools
  */
@@ -668,8 +681,8 @@
 
 /**
  * Delete reported extension erors.
- * @param {DeleteExtensionErrorsProperties} properties The properties specifying
- *     the errors to remove.
+ * @param {!chrome.developerPrivate.DeleteExtensionErrorsProperties} properties
+ *     The properties specifying the errors to remove.
  * @param {function():void=} callback
  * @see https://developer.chrome.com/extensions/developerPrivate#method-deleteExtensionErrors
  */
@@ -711,8 +724,8 @@
 
 /**
  * Updates an extension command.
- * @param {ExtensionCommandUpdate} update The parameters for updating the
- *     extension command.
+ * @param {!chrome.developerPrivate.ExtensionCommandUpdate} update The
+ *     parameters for updating the extension command.
  * @param {function():void=} callback
  * @see https://developer.chrome.com/extensions/developerPrivate#method-updateExtensionCommand
  */
@@ -746,7 +759,7 @@
 chrome.developerPrivate.allowFileAccess = function(extensionId, allow, callback) {};
 
 /**
- * @param {InspectOptions} options
+ * @param {!chrome.developerPrivate.InspectOptions} options
  * @param {function():void=} callback
  * @deprecated Use openDevTools
  * @see https://developer.chrome.com/extensions/developerPrivate#method-inspect
diff --git a/third_party/closure_compiler/runner/runner.jar b/third_party/closure_compiler/runner/runner.jar
index 62c63547..c000f4d 100644
--- a/third_party/closure_compiler/runner/runner.jar
+++ b/third_party/closure_compiler/runner/runner.jar
Binary files differ
diff --git a/third_party/closure_compiler/runner/src/org/chromium/closure/compiler/ChromeCodingConvention.java b/third_party/closure_compiler/runner/src/org/chromium/closure/compiler/ChromeCodingConvention.java
index 396ae82..7eadc53f 100644
--- a/third_party/closure_compiler/runner/src/org/chromium/closure/compiler/ChromeCodingConvention.java
+++ b/third_party/closure_compiler/runner/src/org/chromium/closure/compiler/ChromeCodingConvention.java
@@ -67,4 +67,21 @@
       new AssertInstanceofSpec("cr.ui.decorate")
     );
   }
+
+  // TODO(dbeam): combine this with ClosureCodingConvention?
+  @Override
+  public boolean isFunctionCallThatAlwaysThrows(Node n) {
+    if (n.isExprResult()) {
+      if (!n.getFirstChild().isCall()) {
+        return false;
+      }
+    } else if (!n.isCall()) {
+      return false;
+    }
+    if (n.isExprResult()) {
+      n = n.getFirstChild();
+    }
+    // n is a call
+    return n.getFirstChild().matchesQualifiedName("assertNotReached");
+  }
 }
diff --git a/third_party/opus/BUILD.gn b/third_party/opus/BUILD.gn
index cc3d3cd..339ad967b 100644
--- a/third_party/opus/BUILD.gn
+++ b/third_party/opus/BUILD.gn
@@ -18,6 +18,10 @@
 
 config("opus_config") {
   include_dirs = [ "src/include" ]
+
+  if (use_opus_fixed_point) {
+    defines = [ "OPUS_FIXED_POINT" ]
+  }
 }
 
 config("opus_test_config") {
diff --git a/tools/metrics/actions/extract_actions.py b/tools/metrics/actions/extract_actions.py
index 218c8f2..320b3cf 100755
--- a/tools/metrics/actions/extract_actions.py
+++ b/tools/metrics/actions/extract_actions.py
@@ -191,8 +191,8 @@
     if match:  # Plain call to RecordAction
       actions.add(match.group(1))
 
-def AddClosedSourceActions(actions):
-  """Add actions that are in code which is not checked out by default
+def AddPDFPluginActions(actions):
+  """Add actions that are sent by the PDF plugin.
 
   Arguments
     actions: set of actions to add to.
@@ -740,9 +740,9 @@
   AddAutomaticResetBannerActions(actions)
   AddBookmarkManagerActions(actions)
   AddChromeOSActions(actions)
-  AddClosedSourceActions(actions)
   AddExtensionActions(actions)
   AddHistoryPageActions(actions)
+  AddPDFPluginActions(actions)
 
   return PrettyPrint(actions, actions_dict, comment_nodes)
 
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 38d7916..d8a960f 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -30916,6 +30916,14 @@
   </summary>
 </histogram>
 
+<histogram name="PDF.DocumentFeature" enum="PDFFeatures">
+  <owner>tsergeant@chromium.org</owner>
+  <summary>
+    Tracks which features are used by documents opened in the PDF viewer, logged
+    when the document finishes loading.
+  </summary>
+</histogram>
+
 <histogram name="Pepper.InterfaceUsed" enum="PepperInterface">
   <owner>mackinlay@google.com</owner>
   <owner>teravest@chromium.org</owner>
@@ -68204,6 +68212,12 @@
   <int value="3" label="Server failed"/>
 </enum>
 
+<enum name="PDFFeatures" type="int">
+  <int value="0" label="Loaded Document"/>
+  <int value="1" label="Has Title"/>
+  <int value="2" label="Has Bookmarks"/>
+</enum>
+
 <enum name="PeerConnectionCounters" type="int">
   <int value="0" label="PeerConnection enabled with IPv4."/>
   <int value="1" label="PeerConnection enabled with Ipv6."/>
diff --git a/tools/perf/core/test_data/__init__.py b/tools/perf/core/test_data/__init__.py
new file mode 100644
index 0000000..50b23df
--- /dev/null
+++ b/tools/perf/core/test_data/__init__.py
@@ -0,0 +1,3 @@
+# 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.
diff --git a/tools/perf/core/test_data/complex_benchmarks_case.py b/tools/perf/core/test_data/complex_benchmarks_case.py
index 14236819..4226b22f 100644
--- a/tools/perf/core/test_data/complex_benchmarks_case.py
+++ b/tools/perf/core/test_data/complex_benchmarks_case.py
@@ -4,7 +4,7 @@
 
 
 from core import perf_benchmark
-import simple_benchmarks_case
+from core.test_data import simple_benchmarks_case
 
 
 class TestBenchmarkComplexFoo(perf_benchmark.PerfBenchmark):
diff --git a/tools/telemetry/telemetry/internal/backends/chrome/android_browser_backend.py b/tools/telemetry/telemetry/internal/backends/chrome/android_browser_backend.py
index 177268a..fcff75a 100644
--- a/tools/telemetry/telemetry/internal/backends/chrome/android_browser_backend.py
+++ b/tools/telemetry/telemetry/internal/backends/chrome/android_browser_backend.py
@@ -167,6 +167,12 @@
     args.append('--enable-remote-debugging')
     args.append('--disable-fre')
     args.append('--disable-external-intent-requests')
+
+    trace_config_file = (self.platform_backend.tracing_controller_backend
+                         .GetChromeTraceConfigFile())
+    if trace_config_file:
+      args.append('--trace-config-file=%s' % trace_config_file)
+
     return args
 
   @property
diff --git a/tools/valgrind/gtest_exclude/remoting_unittests.gtest_mac.txt b/tools/valgrind/gtest_exclude/remoting_unittests.gtest_mac.txt
deleted file mode 100644
index 585b98401..0000000
--- a/tools/valgrind/gtest_exclude/remoting_unittests.gtest_mac.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-# Failing on Mac. https://crbug.com/543431
-JingleSessionTest.TestQuicStreamChannel
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 0a61f5d0..74a858f 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -538,32 +538,6 @@
    fun:_ZN7content45ManifestParserTest_IconDensityParseRules_Test8TestBodyEv
 }
 {
-   bug_484444
-   Memcheck:Leak
-   fun:_Znw*
-   ...
-   fun:_ZN4mojo7BindingINS_15ServiceProviderEE4BindENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEPK15MojoAsyncWaiter
-   fun:_ZN4mojo7BindingINS_15ServiceProviderEE4BindENS_16InterfaceRequestIS1_EEPK15MojoAsyncWaiter
-   fun:_ZN7content19ServiceRegistryImpl4BindEN4mojo16InterfaceRequestINS1_15ServiceProviderEEE
-}
-{
-   bug_484444b
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN4mojo8internal11FilterChain6AppendINS0_22MessageHeaderValidatorEEEvv
-   fun:_ZN4mojo8internal17InterfacePtrStateINS_15ServiceProviderEE25ConfigureProxyIfNecessaryEv
-   fun:_ZN4mojo8internal17InterfacePtrStateINS_15ServiceProviderEE8instanceEv
-}
-{
-   bug_484444c
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN4mojo8internal10SharedDataIPNS0_6RouterEEC2ERKS3_
-   fun:_ZN4mojo8internal6RouterC1ENS_16ScopedHandleBaseINS_17MessagePipeHandleEEENS0_11FilterChainEPK15MojoAsyncWaiter
-   fun:_ZN4mojo8internal17InterfacePtrStateINS_15ServiceProviderEE25ConfigureProxyIfNecessaryEv
-   fun:_ZN4mojo8internal17InterfacePtrStateINS_15ServiceProviderEE8instanceEv
-}
-{
    bug_512466
    Memcheck:Leak
    fun:_Znw*
@@ -2464,7 +2438,7 @@
    fun:_ZN5blink4Heap19checkAndMarkPointerEPNS_7VisitorEPh
    fun:_ZN5blink11ThreadState10visitStackEPNS_7VisitorE
    ...
-   fun:_ZN5blink4Heap14collectGarbageENS_11ThreadState10StackState*
+   fun:_ZN5blink4Heap14collectGarbageENS_7BlinkGC10StackState*
 }
 {
    bug_342591
@@ -2611,41 +2585,6 @@
    fun:_ZN3WTFL18callFunctionObjectEPv
 }
 {
-   bug_367809_a
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN4mojo6common13HandleWatcher5StartERKNS_6HandleEjmRKN4base8CallbackIFviEEE
-   fun:_ZN4mojo8internal12_GLOBAL__N_19AsyncWaitEP15MojoAsyncWaiterjjmPFvPviES4_
-   fun:_ZN4mojo8internal9Connector14WaitToReadMoreEv
-   fun:_ZN4mojo8internal9ConnectorC1ENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEP15MojoAsyncWaiter
-   fun:_ZN4mojo8internal6RouterC1ENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEP15MojoAsyncWaiter
-   fun:_ZN4mojo9RemotePtrINS_11ShellClientEE5StateC1ENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEPNS_5ShellEPNS_12ErrorHandlerEP15MojoAsyncWaiter
-   fun:_ZN4mojo9RemotePtrINS_11ShellClientEE5resetENS_16ScopedHandleBaseINS_15InterfaceHandleIS1_EEEEPNS_5ShellEPNS_12ErrorHandlerEP15MojoAsyncWaiter
-   fun:_ZN7content19MojoApplicationHost4InitEv
-}
-{
-   bug_367809_b
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN4mojo8internal12_GLOBAL__N_19AsyncWaitEP15MojoAsyncWaiterjjmPFvPviES4_
-   fun:_ZN4mojo8internal9Connector14WaitToReadMoreEv
-   fun:_ZN4mojo8internal9ConnectorC1ENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEP15MojoAsyncWaiter
-   fun:_ZN4mojo8internal6RouterC1ENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEP15MojoAsyncWaiter
-   fun:_ZN4mojo9RemotePtrINS_11ShellClientEE5StateC1ENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEPNS_5ShellEPNS_12ErrorHandlerEP15MojoAsyncWaiter
-   fun:_ZN4mojo9RemotePtrINS_11ShellClientEE5resetENS_16ScopedHandleBaseINS_15InterfaceHandleIS1_EEEEPNS_5ShellEPNS_12ErrorHandlerEP15MojoAsyncWaiter
-   fun:_ZN7content19MojoApplicationHost4InitEv
-}
-{
-   bug_367809_c
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN4mojo8internal10SharedDataIPNS0_6RouterEEC1ERKS3_
-   fun:_ZN4mojo8internal6RouterC1ENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEP15MojoAsyncWaiter
-   fun:_ZN4mojo9RemotePtrINS_11ShellClientEE5StateC1ENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEPNS_5ShellEPNS_12ErrorHandlerEP15MojoAsyncWaiter
-   fun:_ZN4mojo9RemotePtrINS_11ShellClientEE5resetENS_16ScopedHandleBaseINS_15InterfaceHandleIS1_EEEEPNS_5ShellEPNS_12ErrorHandlerEP15MojoAsyncWaiter
-   fun:_ZN7content19MojoApplicationHost4InitEv
-}
-{
    bug_367809_d
    Memcheck:Leak
    fun:_Znw*
@@ -2679,55 +2618,6 @@
    fun:_ZN7testing8internal15TestFactoryImplIN8feedback*
 }
 {
-   bug_372487_a
-   Memcheck:Leak
-   fun:_Znw*
-   ...
-   fun:_ZN4mojo10BindToPipeIN7content19MojoApplicationHost9ShellImplEEEPT_S5_NS_16ScopedHandleBaseINS_17MessagePipeHandleEEEP15MojoAsyncWaiter
-   fun:_ZN7content19MojoApplicationHost4InitEv
-   fun:_ZN7content21RenderProcessHostImpl4InitEv
-   fun:_ZN7content18RenderViewHostImpl16CreateRenderViewERKSbItN4base20string16_char_traitsESaItEEiib
-   fun:_ZN7content15WebContentsImpl32CreateRenderViewForRenderManagerEPNS_14RenderViewHostEiPNS_26CrossProcessFrameConnectorE
-   fun:_ZN7content22RenderFrameHostManager14InitRenderViewEPNS_14RenderViewHostEi
-   fun:_ZN7content22RenderFrameHostManager8NavigateERKNS_19NavigationEntryImplE
-   fun:_ZN7content13NavigatorImpl15NavigateToEntryEPNS_19RenderFrameHostImplERKNS_19NavigationEntryImplENS_20NavigationController10ReloadTypeE
-   fun:_ZN7content13NavigatorImpl22NavigateToPendingEntryEPNS_19RenderFrameHostImplENS_20NavigationController10ReloadTypeE
-   fun:_ZN7content15WebContentsImpl22NavigateToPendingEntryENS_20NavigationController10ReloadTypeE
-   fun:_ZN7content24NavigationControllerImpl22NavigateToPendingEntryENS_20NavigationController10ReloadTypeE
-   fun:_ZN7content24NavigationControllerImpl9LoadEntryEPNS_19NavigationEntryImplE
-   fun:_ZN7content24NavigationControllerImpl17LoadURLWithParamsERKNS_20NavigationController13LoadURLParamsE
-   fun:_ZN7content5Shell15LoadURLForFrameERK4GURLRKSs
-   fun:_ZN7content5Shell7LoadURLERK4GURL
-   fun:_ZN7content19BlinkTestController20PrepareForLayoutTestERK4GURLRKN4base8FilePathEbRKSs
-   fun:_ZN12_GLOBAL__N_110RunOneTestERKSsPbRK10scoped_ptrIN7content17BrowserMainRunnerEN4base14DefaultDeleterIS5_EEE
-   fun:_Z16ShellBrowserMainRKN7content18MainFunctionParamsERK10scoped_ptrINS_17BrowserMainRunnerEN4base14DefaultDeleterIS4_EEE
-   fun:_ZN7content17ShellMainDelegate10RunProcessERKSsRKNS_18MainFunctionParamsE
-   fun:_ZN7content23RunNamedProcessTypeMainERKSsRKNS_18MainFunctionParamsEPNS_19ContentMainDelegateE
-}
-{
-   bug_372487_b
-   Memcheck:Leak
-   fun:_Znw*
-   ...
-   fun:_ZN4mojo8internal6RouterC1ENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEP15MojoAsyncWaiter
-   fun:_ZN4mojo8internal18InterfaceImplStateINS_5ShellEE4BindENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEP15MojoAsyncWaiter
-   fun:_ZN4mojo10BindToPipeIN7content19MojoApplicationHost9ShellImplEEEPT_S5_NS_16ScopedHandleBaseINS_17MessagePipeHandleEEEP15MojoAsyncWaiter
-   fun:_ZN7content19MojoApplicationHost4InitEv
-   fun:_ZN7content21RenderProcessHostImpl4InitEv
-   fun:_ZN7content18RenderViewHostImpl16CreateRenderViewERKSbItN4base20string16_char_traitsESaItEEiib
-   fun:_ZN7content15WebContentsImpl32CreateRenderViewForRenderManagerEPNS_14RenderViewHostEiPNS_26CrossProcessFrameConnectorE
-   fun:_ZN7content22RenderFrameHostManager14InitRenderViewEPNS_14RenderViewHostEi
-   fun:_ZN7content22RenderFrameHostManager8NavigateERKNS_19NavigationEntryImplE
-   fun:_ZN7content13NavigatorImpl15NavigateToEntryEPNS_19RenderFrameHostImplERKNS_19NavigationEntryImplENS_20NavigationController10ReloadTypeE
-   fun:_ZN7content13NavigatorImpl22NavigateToPendingEntryEPNS_19RenderFrameHostImplENS_20NavigationController10ReloadTypeE
-   fun:_ZN7content15WebContentsImpl22NavigateToPendingEntryENS_20NavigationController10ReloadTypeE
-   fun:_ZN7content24NavigationControllerImpl22NavigateToPendingEntryENS_20NavigationController10ReloadTypeE
-   fun:_ZN7content24NavigationControllerImpl9LoadEntryEPNS_19NavigationEntryImplE
-   fun:_ZN7content24NavigationControllerImpl17LoadURLWithParamsERKNS_20NavigationController13LoadURLParamsE
-   fun:_ZN7content5Shell15LoadURLForFrameERK4GURLRKSs
-   fun:_ZN7content5Shell7LoadURLERK4GURL
-}
-{
    bug_379943
    Memcheck:Leak
    fun:_Znw*
@@ -3282,24 +3172,6 @@
    fun:_ZN4base12_GLOBAL__N_110ThreadFuncEPv
 }
 {
-   bug_455732
-   Memcheck:Leak
-   fun:_Znw*
-   ...
-   fun:_ZN7content12_GLOBAL__N_120ApplicationSetupImpl24ExchangeServiceProvidersEN4mojo16InterfaceRequestINS2_15ServiceProviderEEENS2_12InterfacePtrIS4_EE
-   fun:_ZN7content20ApplicationSetupStub6AcceptEPN4mojo7MessageE
-   fun:_ZN4mojo8internal6Router21HandleIncomingMessageEPNS_7MessageE
-   fun:_ZN4mojo8internal6Router26HandleIncomingMessageThunk6AcceptEPNS_7MessageE
-   fun:_ZN7content32ApplicationSetupRequestValidator6AcceptEPN4mojo7MessageE
-   fun:_ZN4mojo8internal22MessageHeaderValidator6AcceptEPNS_7MessageE
-   fun:_ZN4mojo22ReadAndDispatchMessageENS_17MessagePipeHandleEPNS_15MessageReceiverEPb
-   fun:_ZN4mojo8internal9Connector17ReadSingleMessageEPi
-   fun:_ZN4mojo8internal9Connector24ReadAllAvailableMessagesEv
-   fun:_ZN4mojo8internal9Connector13OnHandleReadyEi
-   fun:_ZN4mojo8internal9Connector17CallOnHandleReadyEPvi
-   fun:_ZN4mojo8internal12_GLOBAL__N_113OnHandleReadyEPNS_6common13HandleWatcherEPFvPviES5_i
-}
-{
    bug_476940
    Memcheck:Leak
    fun:malloc
@@ -3405,7 +3277,7 @@
    fun:_ZN5blink13CallbackStack4Item4callEPNS_7VisitorE
    fun:_ZN5blink4Heap25popAndInvokeTraceCallbackEPNS_7VisitorE
    fun:_ZN5blink4Heap19processMarkingStackEPNS_7VisitorE
-   fun:_ZN5blink4Heap14collectGarbageENS_11ThreadState10StackStateENS1_6GCTypeENS0_8GCReasonE
+   fun:_ZN5blink4Heap14collectGarbageENS_7BlinkGC10StackStateENS1_6GCTypeENS0_8GCReasonE
    fun:_ZN5blink14V8GCController10gcEpilogueEN2v86GCTypeENS1_15GCCallbackFlagsE
    fun:_ZN2v88internal4Heap23CallGCEpilogueCallbacksENS_6GCTypeENS_15GCCallbackFlagsE
    fun:_ZN2v88internal4Heap24PerformGarbageCollectionENS0_16GarbageCollectorENS_15GCCallbackFlagsE
@@ -3504,26 +3376,6 @@
    fun:_ZN7content5Shell15LoadURLForFrameERK4GURLRKSs
 }
 {
-   bug_536907_b
-   Memcheck:Leak
-   fun:_Znw*
-   ...
-   fun:_ZNSt3mapISsN4base8CallbackIFvN4mojo16ScopedHandleBaseINS2_17MessagePipeHandleEEEEEESt4lessISsESaISt4pairIKSsS7_EEEixERSB_
-   fun:_ZN7content19ServiceRegistryImpl10AddServiceERKSsN4base8CallbackIFvN4mojo16ScopedHandleBaseINS5_17MessagePipeHandleEEEEEE
-   fun:_ZN7content15ServiceRegistry10AddServiceIN6device14BatteryMonitorEEEvN4base8CallbackIFvN4mojo16InterfaceRequestIT_EEEEE
-   fun:_ZN7content21RenderProcessHostImpl20RegisterMojoServicesEv
-   fun:_ZN7content21RenderProcessHostImpl4InitEv
-   fun:_ZN7content22RenderFrameHostManager14InitRenderViewEPNS_18RenderViewHostImplEi
-   fun:_ZN7content22RenderFrameHostManager8NavigateERK4GURLRKNS_20FrameNavigationEntryERKNS_19NavigationEntryImplE
-   fun:_ZN7content13NavigatorImpl15NavigateToEntryEPNS_13FrameTreeNodeERKNS_20FrameNavigationEntryERKNS_19NavigationEntryImplENS_20NavigationController10ReloadTypeEb
-   fun:_ZN7content13NavigatorImpl22NavigateToPendingEntryEPNS_13FrameTreeNodeERKNS_20FrameNavigationEntryENS_20NavigationController10ReloadTypeEb
-   fun:_ZN7content24NavigationControllerImpl30NavigateToPendingEntryInternalENS_20NavigationController10ReloadTypeE
-   fun:_ZN7content24NavigationControllerImpl22NavigateToPendingEntryENS_20NavigationController10ReloadTypeE
-   fun:_ZN7content24NavigationControllerImpl9LoadEntryE10scoped_ptrINS_19NavigationEntryImplEN4base14DefaultDeleterIS2_EEE
-   fun:_ZN7content24NavigationControllerImpl17LoadURLWithParamsERKNS_20NavigationController13LoadURLParamsE
-   fun:_ZN7content5Shell15LoadURLForFrameERK4GURLRKSs
-}
-{
    bug_542543
    Memcheck:Leak
    fun:_Znw*
diff --git a/tools/vim/ninja_output.py b/tools/vim/ninja_output.py
index a2d1268..fab26eb 100644
--- a/tools/vim/ninja_output.py
+++ b/tools/vim/ninja_output.py
@@ -45,7 +45,9 @@
         if os.path.isdir(out):
           output_dirs.append(os.path.relpath(out, start = chrome_root))
 
-  configs = [configuration] if configuration else ['Debug', 'Release']
+  configs = ['Debug', 'Release', 'Default']
+  if configuration:
+    configs = [configuration]
 
   def generate_paths():
     for out_dir, config in itertools.product(output_dirs, configs):
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 6fad1dc..9a1e225 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -127,6 +127,7 @@
     "hit_test.h",
     "idle/idle.cc",
     "idle/idle.h",
+    "idle/idle_android.cc",
     "idle/idle_chromeos.cc",
     "idle/idle_linux.cc",
     "idle/idle_mac.mm",
@@ -570,10 +571,14 @@
   }
 
   if (is_android || is_ios) {
+    sources -= [ "device_form_factor_desktop.cc" ]
+  }
+
+  if ((is_android && !use_aura) || is_ios) {
     sources -= [
-      "device_form_factor_desktop.cc",
       "idle/idle.cc",
       "idle/idle.h",
+      "idle/idle_android.cc",
     ]
   }
 }
diff --git a/ui/base/idle/idle_android.cc b/ui/base/idle/idle_android.cc
new file mode 100644
index 0000000..43b27c0
--- /dev/null
+++ b/ui/base/idle/idle_android.cc
@@ -0,0 +1,21 @@
+// 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 "ui/base/idle/idle.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+void CalculateIdleTime(IdleTimeCallback notify) {
+  NOTIMPLEMENTED();
+  notify.Run(0);
+}
+
+bool CheckIdleStateIsLocked() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace ui
diff --git a/ui/base/ui_base.gyp b/ui/base/ui_base.gyp
index 487d2b3..417599e 100644
--- a/ui/base/ui_base.gyp
+++ b/ui/base/ui_base.gyp
@@ -198,6 +198,7 @@
         'hit_test.h',
         'idle/idle.cc',
         'idle/idle.h',
+        'idle/idle_android.cc',
         'idle/idle_chromeos.cc',
         'idle/idle_linux.cc',
         'idle/idle_mac.mm',
@@ -584,8 +585,6 @@
             'default_theme_provider.cc',
             'dragdrop/drag_utils.cc',
             'dragdrop/drag_utils.h',
-            'idle/idle.cc',
-            'idle/idle.h',
             'l10n/l10n_font_util.cc',
             'models/button_menu_item_model.cc',
             'models/dialog_model.cc',
@@ -606,7 +605,10 @@
         }],
         ['OS=="android" and use_aura==0', {
           'sources!': [
-            'cursor/cursor_android.cc'
+            'cursor/cursor_android.cc',
+            'idle/idle.cc',
+            'idle/idle.h',
+            'idle/idle_android.cc',
           ],
         }],
         ['OS=="android" and use_aura==1', {
diff --git a/ui/compositor/callback_layer_animation_observer.cc b/ui/compositor/callback_layer_animation_observer.cc
index 305bce6..639caf4 100644
--- a/ui/compositor/callback_layer_animation_observer.cc
+++ b/ui/compositor/callback_layer_animation_observer.cc
@@ -4,22 +4,39 @@
 
 #include "ui/compositor/callback_layer_animation_observer.h"
 
+#include "base/bind.h"
 #include "ui/compositor/layer_animation_sequence.h"
 
 namespace ui {
 
+void CallbackLayerAnimationObserver::DummyAnimationStartedCallback(
+    const CallbackLayerAnimationObserver&) {}
+
+bool CallbackLayerAnimationObserver::DummyAnimationEndedCallback(
+    bool should_delete_observer,
+    const CallbackLayerAnimationObserver&) {
+  return should_delete_observer;
+}
+
 CallbackLayerAnimationObserver::CallbackLayerAnimationObserver(
     AnimationStartedCallback animation_started_callback,
     AnimationEndedCallback animation_ended_callback)
-    : active_(false),
-      attached_sequence_count_(0),
-      detached_sequence_count_(0),
-      started_count_(0),
-      aborted_count_(0),
-      successful_count_(0),
-      animation_started_callback_(animation_started_callback),
-      animation_ended_callback_(animation_ended_callback),
-      destroyed_(nullptr) {}
+    : animation_started_callback_(animation_started_callback),
+      animation_ended_callback_(animation_ended_callback) {}
+
+CallbackLayerAnimationObserver::CallbackLayerAnimationObserver(
+    AnimationStartedCallback animation_started_callback,
+    bool should_delete_observer)
+    : animation_started_callback_(animation_started_callback),
+      animation_ended_callback_(base::Bind(
+          &CallbackLayerAnimationObserver::DummyAnimationEndedCallback,
+          should_delete_observer)) {}
+
+CallbackLayerAnimationObserver::CallbackLayerAnimationObserver(
+    AnimationEndedCallback animation_ended_callback)
+    : animation_started_callback_(base::Bind(
+          &CallbackLayerAnimationObserver::DummyAnimationStartedCallback)),
+      animation_ended_callback_(animation_ended_callback) {}
 
 CallbackLayerAnimationObserver::~CallbackLayerAnimationObserver() {
   if (destroyed_)
diff --git a/ui/compositor/callback_layer_animation_observer.h b/ui/compositor/callback_layer_animation_observer.h
index 236f1a2..cff5fb4 100644
--- a/ui/compositor/callback_layer_animation_observer.h
+++ b/ui/compositor/callback_layer_animation_observer.h
@@ -69,9 +69,44 @@
   typedef base::Callback<bool(const CallbackLayerAnimationObserver&)>
       AnimationEndedCallback;
 
+  // A dummy no-op AnimationStartedCallback.
+  static void DummyAnimationStartedCallback(
+      const CallbackLayerAnimationObserver&);
+
+  // A dummy no-op AnimationEndedCallback that will return
+  // |should_delete_observer|.
+  //
+  // Example usage:
+  //
+  //    ui::CallbackLayerAnimationObserver* animation_observer =
+  //        new ui::CallbackLayerAnimationObserver(
+  //            base::Bind(&ui::CallbackLayerAnimationObserver::
+  //                DummyAnimationStartedCallback),
+  //            base::Bind(&ui::CallbackLayerAnimationObserver::
+  //                DummyAnimationEndedCallback, false));
+  static bool DummyAnimationEndedCallback(
+      bool should_delete_observer,
+      const CallbackLayerAnimationObserver&);
+
+  // Create an instance that will invoke the |animation_started_callback| when
+  // the animation has started and the |animation_ended_callback| when the
+  // animation has ended.
   CallbackLayerAnimationObserver(
       AnimationStartedCallback animation_started_callback,
       AnimationEndedCallback animation_ended_callback);
+
+  // Create an instance that will invoke the |animation_started_callback| when
+  // the animation has started and will delete |this| when the animations have
+  // ended if |should_delete_observer| is true.
+  CallbackLayerAnimationObserver(
+      AnimationStartedCallback animation_started_callback,
+      bool should_delete_observer);
+
+  // Create an instance that will invoke the |animation_ended_callback| when the
+  // animations have ended.
+  explicit CallbackLayerAnimationObserver(
+      AnimationEndedCallback animation_ended_callback);
+
   ~CallbackLayerAnimationObserver() override;
 
   bool active() const { return active_; }
@@ -108,22 +143,22 @@
   void CheckAllSequencesCompleted();
 
   // Allows the callbacks to be invoked when true.
-  bool active_;
+  bool active_ = false;
 
   // The total number of animation sequences that have been attached.
-  int attached_sequence_count_;
+  int attached_sequence_count_ = 0;
 
   // The total number of animation sequences that have been detached.
-  int detached_sequence_count_;
+  int detached_sequence_count_ = 0;
 
   // The number of animation sequences that have been started.
-  int started_count_;
+  int started_count_ = 0;
 
   // The number of animation sequences that were aborted.
-  int aborted_count_;
+  int aborted_count_ = 0;
 
   // The number of animation sequences that completed successfully.
-  int successful_count_;
+  int successful_count_ = 0;
 
   // The callback to invoke once all the animation sequences have been started.
   AnimationStartedCallback animation_started_callback_;
@@ -133,7 +168,7 @@
 
   // Set to true in the destructor (if non-NULL). Used to detect deletion while
   // calling out.
-  bool* destroyed_;
+  bool* destroyed_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(CallbackLayerAnimationObserver);
 };
diff --git a/ui/compositor/callback_layer_animation_observer_unittest.cc b/ui/compositor/callback_layer_animation_observer_unittest.cc
index b5d708fb..f42f561 100644
--- a/ui/compositor/callback_layer_animation_observer_unittest.cc
+++ b/ui/compositor/callback_layer_animation_observer_unittest.cc
@@ -154,6 +154,16 @@
       AnimationStartedCallback animation_started_callback,
       AnimationEndedCallback animation_ended_callback,
       bool* destroyed);
+
+  TestCallbackLayerAnimationObserver(
+      AnimationStartedCallback animation_started_callback,
+      bool should_delete_observer,
+      bool* destroyed);
+
+  TestCallbackLayerAnimationObserver(
+      AnimationEndedCallback animation_ended_callback,
+      bool* destroyed);
+
   ~TestCallbackLayerAnimationObserver() override;
 
  private:
@@ -169,11 +179,33 @@
     : CallbackLayerAnimationObserver(animation_started_callback,
                                      animation_ended_callback),
       destroyed_(destroyed) {
-  (*destroyed_) = false;
+  if (destroyed_)
+    (*destroyed_) = false;
+}
+
+TestCallbackLayerAnimationObserver::TestCallbackLayerAnimationObserver(
+    AnimationStartedCallback animation_started_callback,
+    bool should_delete_observer,
+    bool* destroyed)
+    : CallbackLayerAnimationObserver(animation_started_callback,
+                                     should_delete_observer),
+      destroyed_(destroyed) {
+  if (destroyed_)
+    (*destroyed_) = false;
+}
+
+TestCallbackLayerAnimationObserver::TestCallbackLayerAnimationObserver(
+    AnimationEndedCallback animation_ended_callback,
+    bool* destroyed)
+    : CallbackLayerAnimationObserver(animation_ended_callback),
+      destroyed_(destroyed) {
+  if (destroyed_)
+    (*destroyed_) = false;
 }
 
 TestCallbackLayerAnimationObserver::~TestCallbackLayerAnimationObserver() {
-  (*destroyed_) = true;
+  if (destroyed_)
+    (*destroyed_) = true;
 }
 
 class CallbackLayerAnimationObserverTest : public testing::Test {
@@ -224,13 +256,37 @@
   return sequence;
 }
 
-TEST_F(CallbackLayerAnimationObserverTest, VerifyInitialState) {
-  EXPECT_FALSE(observer_->active());
-  EXPECT_EQ(0, observer_->aborted_count());
-  EXPECT_EQ(0, observer_->successful_count());
+TEST(CallbackLayerAnimationObserverDestructionTest, VerifyFalseAutoDelete) {
+  TestCallbacks callbacks;
+  callbacks.set_should_delete_observer_on_animations_ended(false);
 
-  EXPECT_FALSE(callbacks_->animations_started());
-  EXPECT_FALSE(callbacks_->animations_ended());
+  bool is_destroyed = false;
+
+  TestCallbackLayerAnimationObserver* observer =
+      new TestCallbackLayerAnimationObserver(
+          base::Bind(&TestCallbacks::AnimationsStarted,
+                     base::Unretained(&callbacks)),
+          false, &is_destroyed);
+  observer->SetActive();
+
+  EXPECT_FALSE(is_destroyed);
+  delete observer;
+}
+
+TEST(CallbackLayerAnimationObserverDestructionTest, VerifyTrueAutoDelete) {
+  TestCallbacks callbacks;
+  callbacks.set_should_delete_observer_on_animations_ended(false);
+
+  bool is_destroyed = false;
+
+  TestCallbackLayerAnimationObserver* observer =
+      new TestCallbackLayerAnimationObserver(
+          base::Bind(&TestCallbacks::AnimationsStarted,
+                     base::Unretained(&callbacks)),
+          true, &is_destroyed);
+  observer->SetActive();
+
+  EXPECT_TRUE(is_destroyed);
 }
 
 TEST(CallbackLayerAnimationObserverDestructionTest,
@@ -271,6 +327,15 @@
   EXPECT_TRUE(is_destroyed);
 }
 
+TEST_F(CallbackLayerAnimationObserverTest, VerifyInitialState) {
+  EXPECT_FALSE(observer_->active());
+  EXPECT_EQ(0, observer_->aborted_count());
+  EXPECT_EQ(0, observer_->successful_count());
+
+  EXPECT_FALSE(callbacks_->animations_started());
+  EXPECT_FALSE(callbacks_->animations_ended());
+}
+
 // Verifies that the CallbackLayerAnimationObserver is robust to explicit
 // deletes caused as a side effect of calling the AnimationsStartedCallback()
 // when there are no animation sequences attached. This test also guards against
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index e648c8a..cab5d6e 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -109,7 +109,7 @@
     }
   }
   settings.renderer_settings.partial_swap_enabled =
-      !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap);
+      !command_line->HasSwitch(switches::kUIDisablePartialSwap);
 #if defined(OS_WIN)
   settings.renderer_settings.finish_rendering_on_resize = true;
 #endif
diff --git a/ui/compositor/compositor_switches.cc b/ui/compositor/compositor_switches.cc
index 8a5fb98c..113cd5e 100644
--- a/ui/compositor/compositor_switches.cc
+++ b/ui/compositor/compositor_switches.cc
@@ -15,6 +15,9 @@
 // Forces tests to produce pixel output when they normally wouldn't.
 const char kEnablePixelOutputInTests[] = "enable-pixel-output-in-tests";
 
+// Disable partial swap which is needed for some OpenGL drivers / emulators.
+const char kUIDisablePartialSwap[] = "ui-disable-partial-swap";
+
 const char kUIEnableCompositorAnimationTimelines[] =
     "ui-enable-compositor-animation-timelines";
 
diff --git a/ui/compositor/compositor_switches.h b/ui/compositor/compositor_switches.h
index 683f055..d2fd68c5 100644
--- a/ui/compositor/compositor_switches.h
+++ b/ui/compositor/compositor_switches.h
@@ -11,6 +11,7 @@
 
 COMPOSITOR_EXPORT extern const char kEnableHardwareOverlays[];
 COMPOSITOR_EXPORT extern const char kEnablePixelOutputInTests[];
+COMPOSITOR_EXPORT extern const char kUIDisablePartialSwap[];
 COMPOSITOR_EXPORT extern const char kUIEnableCompositorAnimationTimelines[];
 COMPOSITOR_EXPORT extern const char kUIEnableRGBA4444Textures[];
 COMPOSITOR_EXPORT extern const char kUIEnableZeroCopy[];
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 352a9ce..f370774 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -750,14 +750,6 @@
   cc_layer_->RequestCopyOfOutput(request.Pass());
 }
 
-void Layer::PaintContents(
-    SkCanvas* sk_canvas,
-    const gfx::Rect& clip,
-    ContentLayerClient::PaintingControlSetting painting_control) {
-  // The old non-slimming paint path is not used in ui::Compositor.
-  NOTREACHED();
-}
-
 scoped_refptr<cc::DisplayItemList> Layer::PaintContentsToDisplayList(
     const gfx::Rect& clip,
     ContentLayerClient::PaintingControlSetting painting_control) {
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index 442d55db3..187a3d9f 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -348,10 +348,6 @@
   void RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request);
 
   // ContentLayerClient
-  void PaintContents(
-      SkCanvas* canvas,
-      const gfx::Rect& clip,
-      ContentLayerClient::PaintingControlSetting painting_control) override;
   scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList(
       const gfx::Rect& clip,
       ContentLayerClient::PaintingControlSetting painting_control) override;
diff --git a/ui/mojo/init/screen_mojo.cc b/ui/mojo/init/screen_mojo.cc
index 1ed0d41..2590b6a1 100644
--- a/ui/mojo/init/screen_mojo.cc
+++ b/ui/mojo/init/screen_mojo.cc
@@ -7,17 +7,13 @@
 namespace ui {
 namespace mojo {
 
-ScreenMojo::ScreenMojo(const gfx::Size& screen_size_in_pixels,
-                       float device_pixel_ratio)
-    : screen_size_in_pixels_(screen_size_in_pixels),
-      device_pixel_ratio_(device_pixel_ratio) {
-  static int64 synthesized_display_id = 2000;
-  display_.set_id(synthesized_display_id++);
-  display_.SetScaleAndBounds(device_pixel_ratio,
-                             gfx::Rect(screen_size_in_pixels));
-}
+ScreenMojo::ScreenMojo(const std::vector<gfx::Display>& displays)
+    : displays_(displays) {}
+
+ScreenMojo::~ScreenMojo() {}
 
 gfx::Point ScreenMojo::GetCursorScreenPoint() {
+  NOTIMPLEMENTED();
   return gfx::Point();
 }
 
@@ -32,7 +28,7 @@
 }
 
 gfx::Display ScreenMojo::GetPrimaryDisplay() const {
-  return display_;
+  return displays_[0];
 }
 
 gfx::Display ScreenMojo::GetDisplayNearestWindow(gfx::NativeView view) const {
@@ -44,15 +40,29 @@
 }
 
 int ScreenMojo::GetNumDisplays() const {
-  return 1;
+  return static_cast<int>(displays_.size());
 }
 
 std::vector<gfx::Display> ScreenMojo::GetAllDisplays() const {
-  return std::vector<gfx::Display>(1, GetPrimaryDisplay());
+  return displays_;
 }
 
 gfx::Display ScreenMojo::GetDisplayMatching(const gfx::Rect& match_rect) const {
-  return GetPrimaryDisplay();
+  int biggest_area = 0;
+  gfx::Display result;
+  const gfx::Display matching_display;
+  for (const gfx::Display& display : displays_) {
+    gfx::Rect display_union(match_rect);
+    display_union.Union(display.bounds());
+    if (!display_union.IsEmpty()) {
+      const int area = display_union.width() * display_union.height();
+      if (area > biggest_area) {
+        biggest_area = area;
+        result = display;
+      }
+    }
+  }
+  return biggest_area == 0 ? displays_[0] : result;
 }
 
 void ScreenMojo::AddObserver(gfx::DisplayObserver* observer) {
diff --git a/ui/mojo/init/screen_mojo.h b/ui/mojo/init/screen_mojo.h
index db7f48f..3a3df06 100644
--- a/ui/mojo/init/screen_mojo.h
+++ b/ui/mojo/init/screen_mojo.h
@@ -5,8 +5,9 @@
 #ifndef UI_MOJO_INIT_SCREEN_MOJO_H_
 #define UI_MOJO_INIT_SCREEN_MOJO_H_
 
+#include <vector>
+
 #include "ui/gfx/display.h"
-#include "ui/gfx/geometry/size.h"
 #include "ui/gfx/screen.h"
 
 namespace ui {
@@ -14,7 +15,8 @@
 
 class ScreenMojo : public gfx::Screen {
  public:
-  ScreenMojo(const gfx::Size& screen_size_in_pixels, float device_pixel_ratio);
+  explicit ScreenMojo(const std::vector<gfx::Display>& displays);
+  ~ScreenMojo() override;
 
   // gfx::Screen:
   gfx::Point GetCursorScreenPoint() override;
@@ -30,10 +32,7 @@
   void RemoveObserver(gfx::DisplayObserver* observer) override;
 
  private:
-  const gfx::Size screen_size_in_pixels_;
-  const float device_pixel_ratio_;
-
-  gfx::Display display_;
+  const std::vector<gfx::Display> displays_;
 
   DISALLOW_COPY_AND_ASSIGN(ScreenMojo);
 };
diff --git a/ui/mojo/init/ui_init.cc b/ui/mojo/init/ui_init.cc
index 937112ee..3b4c4ab 100644
--- a/ui/mojo/init/ui_init.cc
+++ b/ui/mojo/init/ui_init.cc
@@ -39,8 +39,8 @@
 };
 #endif
 
-UIInit::UIInit(const gfx::Size& screen_size_in_pixels, float device_pixel_ratio)
-    : screen_(new ScreenMojo(screen_size_in_pixels, device_pixel_ratio)) {
+UIInit::UIInit(const std::vector<gfx::Display>& displays)
+    : screen_(new ScreenMojo(displays)) {
   gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get());
 #if defined(OS_ANDROID)
   gesture_configuration_.reset(new GestureConfigurationMojo);
diff --git a/ui/mojo/init/ui_init.h b/ui/mojo/init/ui_init.h
index eeaebc6..48ca7db 100644
--- a/ui/mojo/init/ui_init.h
+++ b/ui/mojo/init/ui_init.h
@@ -5,13 +5,15 @@
 #ifndef UI_MOJO_INIT_UI_INIT_H_
 #define UI_MOJO_INIT_UI_INIT_H_
 
+#include <vector>
+
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
 #include "base/memory/scoped_ptr.h"
 
 namespace gfx {
+class Display;
 class Screen;
-class Size;
 }
 
 namespace ui {
@@ -25,7 +27,7 @@
 // including aura).
 class UIInit {
  public:
-  UIInit(const gfx::Size& screen_size_in_pixels, float device_pixel_ratio);
+  explicit UIInit(const std::vector<gfx::Display>& displays);
   ~UIInit();
 
  private:
diff --git a/ui/snapshot/BUILD.gn b/ui/snapshot/BUILD.gn
index a9e5b0b..c79a70b3 100644
--- a/ui/snapshot/BUILD.gn
+++ b/ui/snapshot/BUILD.gn
@@ -30,7 +30,7 @@
     "//ui/gfx/geometry",
   ]
 
-  if (is_android) {
+  if (is_android && !use_aura) {
     deps += [ "//ui/android" ]
   }
 
@@ -46,6 +46,10 @@
     ]
   }
 
+  if (is_android && use_aura) {
+    sources -= [ "snapshot_android.cc" ]
+  }
+
   if (use_aura) {
     deps += [
       "//ui/aura",
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index b3a6ada..0391d54 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -482,65 +482,23 @@
   }
 }
 
-bool MenuController::OnMousePressed(SubmenuView* source,
+void MenuController::OnMousePressed(SubmenuView* source,
                                     const ui::MouseEvent& event) {
-  // We should either have no current_mouse_event_target_, or should have a
-  // pressed state stored.
-  DCHECK(!current_mouse_event_target_ || current_mouse_pressed_state_);
-
-  // Find the root view to check. If any buttons were previously pressed, this
-  // is the same root view we've been forwarding to. Otherwise, it's the root
-  // view of the target.
-  MenuHostRootView* forward_to_root =
-      current_mouse_pressed_state_ ? current_mouse_event_target_
-                                   : GetRootView(source, event.location());
-
-  current_mouse_pressed_state_ |= event.changed_button_flags();
-
-  if (forward_to_root) {
-    ui::MouseEvent event_for_root(event);
-    ConvertLocatedEventForRootView(source, forward_to_root, &event_for_root);
-    View* view =
-        forward_to_root->GetEventHandlerForPoint(event_for_root.location());
-    // Empty menu items are always handled by the menu controller.
-    if (!view || view->id() != MenuItemView::kEmptyMenuItemViewID) {
-      bool processed = forward_to_root->ProcessMousePressed(event_for_root);
-      // If the event was processed, the root view becomes our current mouse
-      // handler...
-      if (processed && !current_mouse_event_target_) {
-        current_mouse_event_target_ = forward_to_root;
-      }
-
-      // ...and we always return the result of the current handler.
-      if (current_mouse_event_target_)
-        return processed;
-    }
-  }
-
-  // Otherwise, the menu handles this click directly.
   SetSelectionOnPointerDown(source, event);
-  return true;
 }
 
-bool MenuController::OnMouseDragged(SubmenuView* source,
+void MenuController::OnMouseDragged(SubmenuView* source,
                                     const ui::MouseEvent& event) {
-  if (current_mouse_event_target_) {
-    ui::MouseEvent event_for_root(event);
-    ConvertLocatedEventForRootView(source, current_mouse_event_target_,
-                                   &event_for_root);
-    return current_mouse_event_target_->ProcessMouseDragged(event_for_root);
-  }
-
   MenuPart part = GetMenuPart(source, event.location());
   UpdateScrolling(part);
 
   if (!blocking_run_)
-    return false;
+    return;
 
   if (possible_drag_) {
     if (View::ExceededDragThreshold(event.location() - press_pt_))
       StartDrag(source, press_pt_);
-    return true;
+    return;
   }
   MenuItemView* mouse_menu = NULL;
   if (part.type == MenuPart::MENU_ITEM) {
@@ -553,29 +511,10 @@
     ShowSiblingMenu(source, event.location());
   }
   UpdateActiveMouseView(source, event, mouse_menu);
-
-  return true;
 }
 
 void MenuController::OnMouseReleased(SubmenuView* source,
                                      const ui::MouseEvent& event) {
-  current_mouse_pressed_state_ &= ~event.changed_button_flags();
-
-  if (current_mouse_event_target_) {
-    // If this was the final mouse button, then remove the forwarding target.
-    // We need to do this *before* dispatching the event to the root view
-    // because there's a chance that the event will open a nested (and blocking)
-    // menu, and we need to not have a forwarded root view.
-    MenuHostRootView* cached_event_target = current_mouse_event_target_;
-    if (!current_mouse_pressed_state_)
-      current_mouse_event_target_ = nullptr;
-    ui::MouseEvent event_for_root(event);
-    ConvertLocatedEventForRootView(source, cached_event_target,
-                                   &event_for_root);
-    cached_event_target->ProcessMouseReleased(event_for_root);
-    return;
-  }
-
   if (!blocking_run_)
     return;
 
@@ -650,17 +589,6 @@
 
 void MenuController::OnMouseMoved(SubmenuView* source,
                                   const ui::MouseEvent& event) {
-  if (current_mouse_event_target_) {
-    ui::MouseEvent event_for_root(event);
-    ConvertLocatedEventForRootView(source, current_mouse_event_target_,
-                                   &event_for_root);
-    current_mouse_event_target_->ProcessMouseMoved(event_for_root);
-    return;
-  }
-
-  MenuHostRootView* root_view = GetRootView(source, event.location());
-  if (root_view)
-    root_view->ProcessMouseMoved(event);
   HandleMouseLocation(source, event.location());
 }
 
@@ -724,23 +652,6 @@
   part.submenu->OnGestureEvent(event);
 }
 
-View* MenuController::GetTooltipHandlerForPoint(SubmenuView* source,
-                                                const gfx::Point& point) {
-  MenuHostRootView* root_view = GetRootView(source, point);
-  return root_view ? root_view->ProcessGetTooltipHandlerForPoint(point)
-                   : nullptr;
-}
-
-void MenuController::ViewHierarchyChanged(
-    SubmenuView* source,
-    const View::ViewHierarchyChangedDetails& details) {
-  // If the current mouse handler is removed, remove it as the handler.
-  if (!details.is_add && details.child == current_mouse_event_target_) {
-    current_mouse_event_target_ = nullptr;
-    current_mouse_pressed_state_ = 0;
-  }
-}
-
 bool MenuController::GetDropFormats(
       SubmenuView* source,
       int* formats,
@@ -894,11 +805,6 @@
 void MenuController::OnDragComplete(bool should_close) {
   DCHECK(drag_in_progress_);
   drag_in_progress_ = false;
-  // During a drag, mouse events are processed directly by the widget, and not
-  // sent to the MenuController. At drag completion, reset pressed state and
-  // the event target.
-  current_mouse_pressed_state_ = 0;
-  current_mouse_event_target_ = nullptr;
   if (showing_ && should_close && GetActiveInstance() == this) {
     CloseAllNestedMenus();
     Cancel(EXIT_ALL);
@@ -1243,8 +1149,6 @@
       menu_start_time_(base::TimeTicks()),
       is_combobox_(false),
       item_selected_by_touch_(false),
-      current_mouse_event_target_(nullptr),
-      current_mouse_pressed_state_(0),
       message_loop_(MenuMessageLoop::Create()) {
   active_instance_ = this;
 }
@@ -1524,26 +1428,6 @@
   return true;
 }
 
-MenuHostRootView* MenuController::GetRootView(SubmenuView* submenu,
-                                              const gfx::Point& source_loc) {
-  MenuPart part = GetMenuPart(submenu, source_loc);
-  SubmenuView* view = part.submenu;
-  return view && view->GetWidget()
-             ? static_cast<MenuHostRootView*>(view->GetWidget()->GetRootView())
-             : nullptr;
-}
-
-void MenuController::ConvertLocatedEventForRootView(View* source,
-                                                    View* dst,
-                                                    ui::LocatedEvent* event) {
-  if (source->GetWidget()->GetRootView() == dst)
-    return;
-  gfx::Point new_location(event->location());
-  View::ConvertPointToScreen(source, &new_location);
-  View::ConvertPointFromScreen(dst, &new_location);
-  event->set_location(new_location);
-}
-
 bool MenuController::DoesSubmenuContainLocation(SubmenuView* submenu,
                                                 const gfx::Point& screen_loc) {
   gfx::Point view_loc = screen_loc;
diff --git a/ui/views/controls/menu/menu_controller.h b/ui/views/controls/menu/menu_controller.h
index 0b5344d..1fa1e90 100644
--- a/ui/views/controls/menu/menu_controller.h
+++ b/ui/views/controls/menu/menu_controller.h
@@ -132,16 +132,13 @@
   //
   // NOTE: the coordinates of the events are in that of the
   // MenuScrollViewContainer.
-  bool OnMousePressed(SubmenuView* source, const ui::MouseEvent& event);
-  bool OnMouseDragged(SubmenuView* source, const ui::MouseEvent& event);
+  void OnMousePressed(SubmenuView* source, const ui::MouseEvent& event);
+  void OnMouseDragged(SubmenuView* source, const ui::MouseEvent& event);
   void OnMouseReleased(SubmenuView* source, const ui::MouseEvent& event);
   void OnMouseMoved(SubmenuView* source, const ui::MouseEvent& event);
   void OnMouseEntered(SubmenuView* source, const ui::MouseEvent& event);
   bool OnMouseWheel(SubmenuView* source, const ui::MouseWheelEvent& event);
   void OnGestureEvent(SubmenuView* source, ui::GestureEvent* event);
-  View* GetTooltipHandlerForPoint(SubmenuView* source, const gfx::Point& point);
-  void ViewHierarchyChanged(SubmenuView* source,
-                            const View::ViewHierarchyChangedDetails& details);
 
   bool GetDropFormats(SubmenuView* source,
                       int* formats,
@@ -372,17 +369,6 @@
                                          const gfx::Point& screen_loc,
                                          MenuPart* part);
 
-  // Returns the RootView of the target for the mouse event, if there is a
-  // target at |source_loc|.
-  MenuHostRootView* GetRootView(SubmenuView* source,
-                                const gfx::Point& source_loc);
-
-  // Converts the located event from |source|'s geometry to |dst|'s geometry,
-  // iff the root view of source and dst differ.
-  void ConvertLocatedEventForRootView(View* source,
-                                      View* dst,
-                                      ui::LocatedEvent* event);
-
   // Returns true if the SubmenuView contains the specified location. This does
   // NOT included the scroll buttons, only the submenu view.
   bool DoesSubmenuContainLocation(SubmenuView* submenu,
@@ -655,15 +641,6 @@
   // Set to true if the menu item was selected by touch.
   bool item_selected_by_touch_;
 
-  // During mouse event handling, this is the RootView to forward mouse events
-  // to. We need this, because if we forward one event to it (e.g., mouse
-  // pressed), subsequent events (like dragging) should also go to it, even if
-  // the mouse is no longer over the view.
-  MenuHostRootView* current_mouse_event_target_;
-
-  // A mask of the EventFlags for the mouse buttons currently pressed.
-  int current_mouse_pressed_state_;
-
   scoped_ptr<MenuMessageLoop> message_loop_;
 
   DISALLOW_COPY_AND_ASSIGN(MenuController);
diff --git a/ui/views/controls/menu/menu_host_root_view.cc b/ui/views/controls/menu/menu_host_root_view.cc
index 362971f..1bc834a0 100644
--- a/ui/views/controls/menu/menu_host_root_view.cc
+++ b/ui/views/controls/menu/menu_host_root_view.cc
@@ -10,25 +10,42 @@
 
 namespace views {
 
-MenuHostRootView::MenuHostRootView(Widget* widget, SubmenuView* submenu)
-    : internal::RootView(widget), submenu_(submenu) {}
+MenuHostRootView::MenuHostRootView(Widget* widget,
+                                   SubmenuView* submenu)
+    : internal::RootView(widget),
+      submenu_(submenu),
+      forward_drag_to_menu_controller_(true) {
+}
 
 bool MenuHostRootView::OnMousePressed(const ui::MouseEvent& event) {
-  return GetMenuController() &&
-         GetMenuController()->OnMousePressed(submenu_, event);
+  forward_drag_to_menu_controller_ =
+      !GetLocalBounds().Contains(event.location()) ||
+      !RootView::OnMousePressed(event) ||
+      DoesEventTargetEmptyMenuItem(event);
+
+  if (forward_drag_to_menu_controller_ && GetMenuController())
+    GetMenuController()->OnMousePressed(submenu_, event);
+  return true;
 }
 
 bool MenuHostRootView::OnMouseDragged(const ui::MouseEvent& event) {
-  return GetMenuController() &&
-         GetMenuController()->OnMouseDragged(submenu_, event);
+  if (forward_drag_to_menu_controller_ && GetMenuController()) {
+    GetMenuController()->OnMouseDragged(submenu_, event);
+    return true;
+  }
+  return RootView::OnMouseDragged(event);
 }
 
 void MenuHostRootView::OnMouseReleased(const ui::MouseEvent& event) {
-  if (GetMenuController())
+  RootView::OnMouseReleased(event);
+  if (forward_drag_to_menu_controller_ && GetMenuController()) {
+    forward_drag_to_menu_controller_ = false;
     GetMenuController()->OnMouseReleased(submenu_, event);
+  }
 }
 
 void MenuHostRootView::OnMouseMoved(const ui::MouseEvent& event) {
+  RootView::OnMouseMoved(event);
   if (GetMenuController())
     GetMenuController()->OnMouseMoved(submenu_, event);
 }
@@ -38,40 +55,6 @@
       GetMenuController()->OnMouseWheel(submenu_, event);
 }
 
-View* MenuHostRootView::GetTooltipHandlerForPoint(const gfx::Point& point) {
-  return GetMenuController()
-             ? GetMenuController()->GetTooltipHandlerForPoint(submenu_, point)
-             : nullptr;
-}
-
-void MenuHostRootView::ViewHierarchyChanged(
-    const ViewHierarchyChangedDetails& details) {
-  if (GetMenuController())
-    GetMenuController()->ViewHierarchyChanged(submenu_, details);
-  RootView::ViewHierarchyChanged(details);
-}
-
-bool MenuHostRootView::ProcessMousePressed(const ui::MouseEvent& event) {
-  return RootView::OnMousePressed(event);
-}
-
-bool MenuHostRootView::ProcessMouseDragged(const ui::MouseEvent& event) {
-  return RootView::OnMouseDragged(event);
-}
-
-void MenuHostRootView::ProcessMouseReleased(const ui::MouseEvent& event) {
-  RootView::OnMouseReleased(event);
-}
-
-void MenuHostRootView::ProcessMouseMoved(const ui::MouseEvent& event) {
-  RootView::OnMouseMoved(event);
-}
-
-View* MenuHostRootView::ProcessGetTooltipHandlerForPoint(
-    const gfx::Point& point) {
-  return RootView::GetTooltipHandlerForPoint(point);
-}
-
 void MenuHostRootView::OnEventProcessingFinished(ui::Event* event) {
   RootView::OnEventProcessingFinished(event);
 
@@ -87,4 +70,10 @@
   return submenu_ ? submenu_->GetMenuItem()->GetMenuController() : NULL;
 }
 
+bool MenuHostRootView::DoesEventTargetEmptyMenuItem(
+    const ui::MouseEvent& event) {
+  View* view = GetEventHandlerForPoint(event.location());
+  return view && view->id() == MenuItemView::kEmptyMenuItemViewID;
+}
+
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_host_root_view.h b/ui/views/controls/menu/menu_host_root_view.h
index 1a2aabd..cdb6b40 100644
--- a/ui/views/controls/menu/menu_host_root_view.h
+++ b/ui/views/controls/menu/menu_host_root_view.h
@@ -30,15 +30,6 @@
   void OnMouseReleased(const ui::MouseEvent& event) override;
   void OnMouseMoved(const ui::MouseEvent& event) override;
   bool OnMouseWheel(const ui::MouseWheelEvent& event) override;
-  View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
-  void ViewHierarchyChanged(const ViewHierarchyChangedDetails& details)
-      override;
-
-  bool ProcessMousePressed(const ui::MouseEvent& event);
-  bool ProcessMouseDragged(const ui::MouseEvent& event);
-  void ProcessMouseReleased(const ui::MouseEvent& event);
-  void ProcessMouseMoved(const ui::MouseEvent& event);
-  View* ProcessGetTooltipHandlerForPoint(const gfx::Point& point);
 
  private:
   // ui::EventProcessor:
@@ -47,9 +38,15 @@
   // Returns the MenuController for this MenuHostRootView.
   MenuController* GetMenuController();
 
+  // Returns true if event targets EmptyMenu.
+  bool DoesEventTargetEmptyMenuItem(const ui::MouseEvent& event);
+
   // The SubmenuView we contain.
   SubmenuView* submenu_;
 
+  // Whether mouse dragged/released should be forwarded to the MenuController.
+  bool forward_drag_to_menu_controller_;
+
   DISALLOW_COPY_AND_ASSIGN(MenuHostRootView);
 };
 
diff --git a/ui/views/mus/aura_init.cc b/ui/views/mus/aura_init.cc
index 47aabe5..ddbab0d 100644
--- a/ui/views/mus/aura_init.cc
+++ b/ui/views/mus/aura_init.cc
@@ -7,13 +7,15 @@
 #include "base/i18n/icu_util.h"
 #include "base/lazy_instance.h"
 #include "base/path_service.h"
-#include "components/mus/public/cpp/view.h"
+#include "components/mus/public/cpp/window.h"
 #include "components/resource_provider/public/cpp/resource_loader.h"
+#include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
 #include "ui/aura/env.h"
 #include "ui/base/ime/input_method_initializer.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
+#include "ui/gfx/display.h"
 
 #if defined(OS_LINUX) && !defined(OS_ANDROID)
 #include "components/font_service/public/cpp/font_loader.h"
@@ -29,19 +31,32 @@
   return paths;
 }
 
+std::vector<gfx::Display> GetDisplaysFromWindow(mus::Window* window) {
+  static int64 synthesized_display_id = 2000;
+  gfx::Display display;
+  display.set_id(synthesized_display_id++);
+  display.SetScaleAndBounds(
+      window->viewport_metrics().device_pixel_ratio,
+      gfx::Rect(window->viewport_metrics().size_in_pixels.To<gfx::Size>()));
+  std::vector<gfx::Display> displays;
+  displays.push_back(display);
+  return displays;
+}
+
 }  // namespace
 
-// TODO(sky): the 1.f should be view->viewport_metrics().device_scale_factor,
-// but that causes clipping problems. No doubt we're not scaling a size
-// correctly.
-AuraInit::AuraInit(mus::View* view,
-                   mojo::Shell* shell,
-                   const std::string& resource_file)
-    : ui_init_(view->viewport_metrics().size_in_pixels.To<gfx::Size>(), 1.f),
-      resource_file_(resource_file) {
+AuraInit::AuraInit(mojo::ApplicationImpl* app,
+                   const std::string& resource_file,
+                   mus::Window* window)
+    : AuraInit(app, resource_file, GetDisplaysFromWindow(window)) {}
+
+AuraInit::AuraInit(mojo::ApplicationImpl* app,
+                   const std::string& resource_file,
+                   const std::vector<gfx::Display>& displays)
+    : ui_init_(displays), resource_file_(resource_file) {
   aura::Env::CreateInstance(false);
 
-  InitializeResources(shell);
+  InitializeResources(app);
 
   ui::InitializeInputMethodForTesting();
 }
@@ -58,11 +73,11 @@
 #endif
 }
 
-void AuraInit::InitializeResources(mojo::Shell* shell) {
+void AuraInit::InitializeResources(mojo::ApplicationImpl* app) {
   if (ui::ResourceBundle::HasSharedInstance())
     return;
   resource_provider::ResourceLoader resource_loader(
-      shell, GetResourcePaths(resource_file_));
+      app, GetResourcePaths(resource_file_));
   if (!resource_loader.BlockUntilLoaded())
     return;
   CHECK(resource_loader.loaded());
@@ -79,7 +94,7 @@
 
 // Initialize the skia font code to go ask fontconfig underneath.
 #if defined(OS_LINUX) && !defined(OS_ANDROID)
-  font_loader_ = skia::AdoptRef(new font_service::FontLoader(shell));
+  font_loader_ = skia::AdoptRef(new font_service::FontLoader(app->shell()));
   SkFontConfigInterface::SetGlobal(font_loader_.get());
 #endif
 
diff --git a/ui/views/mus/aura_init.h b/ui/views/mus/aura_init.h
index 319a9c33..daa1b3c 100644
--- a/ui/views/mus/aura_init.h
+++ b/ui/views/mus/aura_init.h
@@ -6,6 +6,7 @@
 #define UI_VIEWS_MUS_AURA_INIT_H_
 
 #include <string>
+#include <vector>
 
 #include "skia/ext/refptr.h"
 #include "ui/mojo/init/ui_init.h"
@@ -14,12 +15,16 @@
 class FontLoader;
 }
 
+namespace gfx {
+class Display;
+}
+
 namespace mojo {
-class Shell;
+class ApplicationImpl;
 }
 
 namespace mus {
-class View;
+class Window;
 }
 
 namespace views {
@@ -28,13 +33,18 @@
 // |resource_file| is the path to the apk file containing the resources.
 class AuraInit {
  public:
-  AuraInit(mus::View* root,
-           mojo::Shell* shell,
-           const std::string& resource_file);
+  // This constructor builds the set of Displays from the ViewportMetrics of
+  // |window|.
+  AuraInit(mojo::ApplicationImpl* app,
+           const std::string& resource_file,
+           mus::Window* window);
+  AuraInit(mojo::ApplicationImpl* app,
+           const std::string& resource_file,
+           const std::vector<gfx::Display>& displays);
   ~AuraInit();
 
  private:
-  void InitializeResources(mojo::Shell* shell);
+  void InitializeResources(mojo::ApplicationImpl* app);
 
   ui::mojo::UIInit ui_init_;
 
diff --git a/ui/views/mus/input_method_mus.cc b/ui/views/mus/input_method_mus.cc
index a7222dd..cea183cb 100644
--- a/ui/views/mus/input_method_mus.cc
+++ b/ui/views/mus/input_method_mus.cc
@@ -4,7 +4,7 @@
 
 #include "ui/views/mus/input_method_mus.h"
 
-#include "components/mus/public/cpp/view.h"
+#include "components/mus/public/cpp/window.h"
 #include "mojo/converters/ime/ime_type_converters.h"
 #include "ui/base/ime/text_input_client.h"
 #include "ui/events/event.h"
@@ -16,8 +16,8 @@
 // InputMethodMUS, public:
 
 InputMethodMUS::InputMethodMUS(ui::internal::InputMethodDelegate* delegate,
-                               mus::View* view)
-    : view_(view) {
+                               mus::Window* window)
+    : window_(window) {
   SetDelegate(delegate);
 }
 
@@ -96,9 +96,9 @@
   mojo::TextInputStatePtr state = mojo::TextInputState::New();
   state->type = mojo::ConvertTo<mojo::TextInputType>(type);
   if (type != ui::TEXT_INPUT_TYPE_NONE)
-    view_->SetImeVisibility(true, state.Pass());
+    window_->SetImeVisibility(true, state.Pass());
   else
-    view_->SetTextInputState(state.Pass());
+    window_->SetTextInputState(state.Pass());
 }
 
 }  // namespace mandoline
diff --git a/ui/views/mus/input_method_mus.h b/ui/views/mus/input_method_mus.h
index da17efa..a9be768 100644
--- a/ui/views/mus/input_method_mus.h
+++ b/ui/views/mus/input_method_mus.h
@@ -8,14 +8,15 @@
 #define UI_VIEWS_MUS_INPUT_METHOD_MUS_H_
 
 namespace mus {
-class View;
+class Window;
 }  // namespace mojo
 
 namespace views {
 
 class InputMethodMUS : public ui::InputMethodBase {
  public:
-  InputMethodMUS(ui::internal::InputMethodDelegate* delegate, mus::View* view);
+  InputMethodMUS(ui::internal::InputMethodDelegate* delegate,
+                 mus::Window* window);
   ~InputMethodMUS() override;
 
  private:
@@ -38,8 +39,8 @@
 
   void UpdateTextInputType();
 
-  // The toplevel view which is not owned by this class.
-  mus::View* view_;
+  // The toplevel window which is not owned by this class.
+  mus::Window* window_;
 
   DISALLOW_COPY_AND_ASSIGN(InputMethodMUS);
 };
diff --git a/ui/views/mus/native_widget_view_manager.cc b/ui/views/mus/native_widget_view_manager.cc
index 43bdb2d4..a08080d 100644
--- a/ui/views/mus/native_widget_view_manager.cc
+++ b/ui/views/mus/native_widget_view_manager.cc
@@ -4,7 +4,7 @@
 
 #include "ui/views/mus/native_widget_view_manager.h"
 
-#include "components/mus/public/cpp/view.h"
+#include "components/mus/public/cpp/window.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
 #include "mojo/converters/input_events/input_events_type_converters.h"
 #include "ui/aura/client/default_capture_client.h"
@@ -34,44 +34,45 @@
   DISALLOW_COPY_AND_ASSIGN(FocusRulesImpl);
 };
 
-class NativeWidgetViewObserver : public mus::ViewObserver {
+class NativeWidgetWindowObserver : public mus::WindowObserver {
  public:
-  NativeWidgetViewObserver(NativeWidgetViewManager* view_manager)
+  NativeWidgetWindowObserver(NativeWidgetViewManager* view_manager)
       : view_manager_(view_manager) {
-    view_manager_->view_->AddObserver(this);
+    view_manager_->window_->AddObserver(this);
   }
 
-  ~NativeWidgetViewObserver() override {
-    if (view_manager_->view_)
-      view_manager_->view_->RemoveObserver(this);
+  ~NativeWidgetWindowObserver() override {
+    if (view_manager_->window_)
+      view_manager_->window_->RemoveObserver(this);
   }
 
  private:
-  // ViewObserver:
-  void OnViewDestroyed(mus::View* view) override {
-    DCHECK_EQ(view, view_manager_->view_);
+  // WindowObserver:
+  void OnWindowDestroyed(mus::Window* view) override {
+    DCHECK_EQ(view, view_manager_->window_);
     view->RemoveObserver(this);
-    view_manager_->view_ = nullptr;
+    view_manager_->window_ = nullptr;
     // TODO(sky): WindowTreeHostMojo assumes the View outlives it.
-    // NativeWidgetViewObserver needs to deal, likely by deleting this.
+    // NativeWidgetWindowObserver needs to deal, likely by deleting this.
   }
 
-  void OnViewBoundsChanged(mus::View* view,
-                           const mojo::Rect& old_bounds,
-                           const mojo::Rect& new_bounds) override {
+  void OnWindowBoundsChanged(mus::Window* view,
+                             const mojo::Rect& old_bounds,
+                             const mojo::Rect& new_bounds) override {
     gfx::Rect view_rect = view->bounds().To<gfx::Rect>();
     view_manager_->SetBounds(gfx::Rect(view_rect.size()));
   }
 
-  void OnViewFocusChanged(mus::View* gained_focus,
-                          mus::View* lost_focus) override {
-    if (gained_focus == view_manager_->view_)
+  void OnWindowFocusChanged(mus::Window* gained_focus,
+                            mus::Window* lost_focus) override {
+    if (gained_focus == view_manager_->window_)
       view_manager_->window_tree_host_->GetInputMethod()->OnFocus();
-    else if (lost_focus == view_manager_->view_)
+    else if (lost_focus == view_manager_->window_)
       view_manager_->window_tree_host_->GetInputMethod()->OnBlur();
   }
 
-  void OnViewInputEvent(mus::View* view, const mojo::EventPtr& event) override {
+  void OnWindowInputEvent(mus::Window* view,
+                          const mojo::EventPtr& event) override {
     scoped_ptr<ui::Event> ui_event(event.To<scoped_ptr<ui::Event>>());
     if (!ui_event)
       return;
@@ -86,7 +87,7 @@
 
   NativeWidgetViewManager* const view_manager_;
 
-  DISALLOW_COPY_AND_ASSIGN(NativeWidgetViewObserver);
+  DISALLOW_COPY_AND_ASSIGN(NativeWidgetWindowObserver);
 };
 
 }  // namespace
@@ -94,9 +95,9 @@
 NativeWidgetViewManager::NativeWidgetViewManager(
     views::internal::NativeWidgetDelegate* delegate,
     mojo::Shell* shell,
-    mus::View* view)
-    : NativeWidgetAura(delegate), view_(view) {
-  window_tree_host_.reset(new WindowTreeHostMojo(shell, view_));
+    mus::Window* window)
+    : NativeWidgetAura(delegate), window_(window) {
+  window_tree_host_.reset(new WindowTreeHostMojo(shell, window_));
   window_tree_host_->InitHost();
 
   focus_client_.reset(new wm::FocusController(new FocusRulesImpl));
@@ -110,7 +111,7 @@
   capture_client_.reset(
       new aura::client::DefaultCaptureClient(window_tree_host_->window()));
 
-  view_observer_.reset(new NativeWidgetViewObserver(this));
+  window_observer_.reset(new NativeWidgetWindowObserver(this));
 }
 
 NativeWidgetViewManager::~NativeWidgetViewManager() {}
@@ -124,7 +125,7 @@
 
 void NativeWidgetViewManager::OnWindowVisibilityChanged(aura::Window* window,
                                                         bool visible) {
-  view_->SetVisible(visible);
+  window_->SetVisible(visible);
   // NOTE: We could also update aura::Window's visibility when the View's
   // visibility changes, but this code isn't going to be around for very long so
   // I'm not bothering.
diff --git a/ui/views/mus/native_widget_view_manager.h b/ui/views/mus/native_widget_view_manager.h
index 0c9df020..9c3247e 100644
--- a/ui/views/mus/native_widget_view_manager.h
+++ b/ui/views/mus/native_widget_view_manager.h
@@ -18,7 +18,7 @@
 }
 
 namespace mus {
-class View;
+class Window;
 }
 
 namespace ui {
@@ -34,7 +34,7 @@
 namespace views {
 
 namespace {
-class NativeWidgetViewObserver;
+class NativeWidgetWindowObserver;
 }
 
 class WindowTreeHostMojo;
@@ -43,22 +43,22 @@
  public:
   NativeWidgetViewManager(views::internal::NativeWidgetDelegate* delegate,
                           mojo::Shell* shell,
-                          mus::View* view);
+                          mus::Window* window);
   ~NativeWidgetViewManager() override;
 
  private:
-  friend class NativeWidgetViewObserver;
+  friend class NativeWidgetWindowObserver;
 
   // Overridden from internal::NativeWidgetAura:
   void InitNativeWidget(const views::Widget::InitParams& in_params) override;
   void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
 
   scoped_ptr<WindowTreeHostMojo> window_tree_host_;
-  scoped_ptr<NativeWidgetViewObserver> view_observer_;
+  scoped_ptr<NativeWidgetWindowObserver> window_observer_;
 
   scoped_ptr<wm::FocusController> focus_client_;
 
-  mus::View* view_;
+  mus::Window* window_;
 
   scoped_ptr<aura::client::DefaultCaptureClient> capture_client_;
 
diff --git a/ui/views/mus/surface_binding.cc b/ui/views/mus/surface_binding.cc
index c622698..168ff50 100644
--- a/ui/views/mus/surface_binding.cc
+++ b/ui/views/mus/surface_binding.cc
@@ -16,8 +16,8 @@
 #include "cc/resources/shared_bitmap_manager.h"
 #include "components/mus/public/cpp/context_provider.h"
 #include "components/mus/public/cpp/output_surface.h"
-#include "components/mus/public/cpp/view.h"
-#include "components/mus/public/cpp/view_tree_connection.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/mus/public/interfaces/gpu.mojom.h"
 #include "mojo/application/public/cpp/connect.h"
 #include "mojo/application/public/interfaces/shell.mojom.h"
@@ -42,26 +42,26 @@
     : public base::RefCounted<PerConnectionState> {
  public:
   static PerConnectionState* Get(mojo::Shell* shell,
-                                 mus::ViewTreeConnection* connection);
+                                 mus::WindowTreeConnection* connection);
 
-  scoped_ptr<cc::OutputSurface> CreateOutputSurface(mus::View* view);
+  scoped_ptr<cc::OutputSurface> CreateOutputSurface(mus::Window* window);
 
  private:
-  typedef std::map<mus::ViewTreeConnection*, PerConnectionState*>
+  typedef std::map<mus::WindowTreeConnection*, PerConnectionState*>
       ConnectionToStateMap;
 
   friend class base::RefCounted<PerConnectionState>;
 
-  PerConnectionState(mojo::Shell* shell, mus::ViewTreeConnection* connection);
+  PerConnectionState(mojo::Shell* shell, mus::WindowTreeConnection* connection);
   ~PerConnectionState();
 
   void Init();
 
   static base::LazyInstance<
-      base::ThreadLocalPointer<ConnectionToStateMap>>::Leaky view_states;
+      base::ThreadLocalPointer<ConnectionToStateMap>>::Leaky window_states;
 
   mojo::Shell* shell_;
-  mus::ViewTreeConnection* connection_;
+  mus::WindowTreeConnection* connection_;
 
   // Set of state needed to create an OutputSurface.
   mojo::GpuPtr gpu_;
@@ -72,26 +72,26 @@
 // static
 base::LazyInstance<base::ThreadLocalPointer<
     SurfaceBinding::PerConnectionState::ConnectionToStateMap>>::Leaky
-    SurfaceBinding::PerConnectionState::view_states;
+    SurfaceBinding::PerConnectionState::window_states;
 
 // static
 SurfaceBinding::PerConnectionState* SurfaceBinding::PerConnectionState::Get(
     mojo::Shell* shell,
-    mus::ViewTreeConnection* connection) {
-  ConnectionToStateMap* view_map = view_states.Pointer()->Get();
-  if (!view_map) {
-    view_map = new ConnectionToStateMap;
-    view_states.Pointer()->Set(view_map);
+    mus::WindowTreeConnection* connection) {
+  ConnectionToStateMap* window_map = window_states.Pointer()->Get();
+  if (!window_map) {
+    window_map = new ConnectionToStateMap;
+    window_states.Pointer()->Set(window_map);
   }
-  if (!(*view_map)[connection]) {
-    (*view_map)[connection] = new PerConnectionState(shell, connection);
-    (*view_map)[connection]->Init();
+  if (!(*window_map)[connection]) {
+    (*window_map)[connection] = new PerConnectionState(shell, connection);
+    (*window_map)[connection]->Init();
   }
-  return (*view_map)[connection];
+  return (*window_map)[connection];
 }
 
 scoped_ptr<cc::OutputSurface>
-SurfaceBinding::PerConnectionState::CreateOutputSurface(mus::View* view) {
+SurfaceBinding::PerConnectionState::CreateOutputSurface(mus::Window* window) {
   // TODO(sky): figure out lifetime here. Do I need to worry about the return
   // value outliving this?
   mojo::CommandBufferPtr cb;
@@ -100,22 +100,22 @@
   scoped_refptr<cc::ContextProvider> context_provider(
       new mus::ContextProvider(cb.PassInterface().PassHandle()));
   return make_scoped_ptr(
-      new mus::OutputSurface(context_provider, view->RequestSurface()));
+      new mus::OutputSurface(context_provider, window->RequestSurface()));
 }
 
 SurfaceBinding::PerConnectionState::PerConnectionState(
     mojo::Shell* shell,
-    mus::ViewTreeConnection* connection)
+    mus::WindowTreeConnection* connection)
     : shell_(shell), connection_(connection) {}
 
 SurfaceBinding::PerConnectionState::~PerConnectionState() {
-  ConnectionToStateMap* view_map = view_states.Pointer()->Get();
-  DCHECK(view_map);
-  DCHECK_EQ(this, (*view_map)[connection_]);
-  view_map->erase(connection_);
-  if (view_map->empty()) {
-    delete view_map;
-    view_states.Pointer()->Set(nullptr);
+  ConnectionToStateMap* window_map = window_states.Pointer()->Get();
+  DCHECK(window_map);
+  DCHECK_EQ(this, (*window_map)[connection_]);
+  window_map->erase(connection_);
+  if (window_map->empty()) {
+    delete window_map;
+    window_states.Pointer()->Set(nullptr);
   }
 }
 
@@ -131,13 +131,14 @@
 
 // SurfaceBinding --------------------------------------------------------------
 
-SurfaceBinding::SurfaceBinding(mojo::Shell* shell, mus::View* view)
-    : view_(view), state_(PerConnectionState::Get(shell, view->connection())) {}
+SurfaceBinding::SurfaceBinding(mojo::Shell* shell, mus::Window* window)
+    : window_(window),
+      state_(PerConnectionState::Get(shell, window->connection())) {}
 
 SurfaceBinding::~SurfaceBinding() {}
 
 scoped_ptr<cc::OutputSurface> SurfaceBinding::CreateOutputSurface() {
-  return state_->CreateOutputSurface(view_);
+  return state_->CreateOutputSurface(window_);
 }
 
 }  // namespace views
diff --git a/ui/views/mus/surface_binding.h b/ui/views/mus/surface_binding.h
index 9d3984d..3fd0c60 100644
--- a/ui/views/mus/surface_binding.h
+++ b/ui/views/mus/surface_binding.h
@@ -17,22 +17,22 @@
 }
 
 namespace mus {
-class View;
+class Window;
 }
 
 namespace views {
 
 // SurfaceBinding is responsible for managing the connections necessary to
-// bind a View to the surfaces service.
+// bind a Window to the surfaces service.
 // Internally SurfaceBinding manages one connection (and related structures) per
 // ViewTreeConnection. That is, all Views from a particular ViewTreeConnection
 // share the same connection.
 class SurfaceBinding {
  public:
-  SurfaceBinding(mojo::Shell* shell, mus::View* view);
+  SurfaceBinding(mojo::Shell* shell, mus::Window* window);
   ~SurfaceBinding();
 
-  // Creates an OutputSurface that renders to the View supplied to the
+  // Creates an OutputSurface that renders to the Window supplied to the
   // constructor.
   scoped_ptr<cc::OutputSurface> CreateOutputSurface();
 
@@ -40,7 +40,7 @@
   class PerConnectionState;
 
   mojo::Shell* shell_;
-  mus::View* view_;
+  mus::Window* window_;
   scoped_refptr<PerConnectionState> state_;
 
   DISALLOW_COPY_AND_ASSIGN(SurfaceBinding);
diff --git a/ui/views/mus/surface_context_factory.cc b/ui/views/mus/surface_context_factory.cc
index e6c8b52d..4ed3da6 100644
--- a/ui/views/mus/surface_context_factory.cc
+++ b/ui/views/mus/surface_context_factory.cc
@@ -7,7 +7,7 @@
 #include "cc/output/output_surface.h"
 #include "cc/resources/shared_bitmap_manager.h"
 #include "cc/surfaces/surface_id_allocator.h"
-#include "components/mus/public/cpp/view.h"
+#include "components/mus/public/cpp/window.h"
 #include "mojo/application/public/interfaces/shell.mojom.h"
 #include "ui/compositor/reflector.h"
 #include "ui/gl/gl_bindings.h"
@@ -26,8 +26,8 @@
 }
 
 SurfaceContextFactory::SurfaceContextFactory(mojo::Shell* shell,
-                                             mus::View* view)
-    : surface_binding_(shell, view), next_surface_id_namespace_(1u) {}
+                                             mus::Window* window)
+    : surface_binding_(shell, window), next_surface_id_namespace_(1u) {}
 
 SurfaceContextFactory::~SurfaceContextFactory() {}
 
diff --git a/ui/views/mus/surface_context_factory.h b/ui/views/mus/surface_context_factory.h
index 5c34bb5..e20e83ac 100644
--- a/ui/views/mus/surface_context_factory.h
+++ b/ui/views/mus/surface_context_factory.h
@@ -15,14 +15,14 @@
 }
 
 namespace mus {
-class View;
+class Window;
 }
 
 namespace views {
 
 class SurfaceContextFactory : public ui::ContextFactory {
  public:
-  SurfaceContextFactory(mojo::Shell* shell, mus::View* view);
+  SurfaceContextFactory(mojo::Shell* shell, mus::Window* window);
   ~SurfaceContextFactory() override;
 
  private:
diff --git a/ui/views/mus/window_tree_host_mus.cc b/ui/views/mus/window_tree_host_mus.cc
index 2d59489c..4e69d0a 100644
--- a/ui/views/mus/window_tree_host_mus.cc
+++ b/ui/views/mus/window_tree_host_mus.cc
@@ -4,7 +4,7 @@
 
 #include "ui/views/mus/window_tree_host_mus.h"
 
-#include "components/mus/public/cpp/view_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
 #include "mojo/application/public/interfaces/shell.mojom.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
 #include "ui/aura/env.h"
@@ -20,11 +20,11 @@
 ////////////////////////////////////////////////////////////////////////////////
 // WindowTreeHostMojo, public:
 
-WindowTreeHostMojo::WindowTreeHostMojo(mojo::Shell* shell, mus::View* view)
-    : view_(view), bounds_(view->bounds().To<gfx::Rect>()) {
-  view_->AddObserver(this);
+WindowTreeHostMojo::WindowTreeHostMojo(mojo::Shell* shell, mus::Window* window)
+    : window_(window), bounds_(window->bounds().To<gfx::Rect>()) {
+  window_->AddObserver(this);
 
-  context_factory_.reset(new SurfaceContextFactory(shell, view_));
+  context_factory_.reset(new SurfaceContextFactory(shell, window_));
   // WindowTreeHost creates the compositor using the ContextFactory from
   // aura::Env. Install |context_factory_| there so that |context_factory_| is
   // picked up.
@@ -36,12 +36,12 @@
   aura::Env::GetInstance()->set_context_factory(default_context_factory);
   DCHECK_EQ(context_factory_.get(), compositor()->context_factory());
 
-  input_method_.reset(new InputMethodMUS(this, view_));
+  input_method_.reset(new InputMethodMUS(this, window_));
   SetSharedInputMethod(input_method_.get());
 }
 
 WindowTreeHostMojo::~WindowTreeHostMojo() {
-  view_->RemoveObserver(this);
+  window_->RemoveObserver(this);
   DestroyCompositor();
   DestroyDispatcher();
 }
@@ -98,9 +98,9 @@
 ////////////////////////////////////////////////////////////////////////////////
 // WindowTreeHostMojo, ViewObserver implementation:
 
-void WindowTreeHostMojo::OnViewBoundsChanged(mus::View* view,
-                                             const mojo::Rect& old_bounds,
-                                             const mojo::Rect& new_bounds) {
+void WindowTreeHostMojo::OnWindowBoundsChanged(mus::Window* window,
+                                               const mojo::Rect& old_bounds,
+                                               const mojo::Rect& new_bounds) {
   gfx::Rect old_bounds2 = old_bounds.To<gfx::Rect>();
   gfx::Rect new_bounds2 = new_bounds.To<gfx::Rect>();
   bounds_ = new_bounds2;
diff --git a/ui/views/mus/window_tree_host_mus.h b/ui/views/mus/window_tree_host_mus.h
index a535195..4de4a01 100644
--- a/ui/views/mus/window_tree_host_mus.h
+++ b/ui/views/mus/window_tree_host_mus.h
@@ -6,7 +6,7 @@
 #define UI_VIEWS_MUS_WINDOW_TREE_HOST_MUS_H_
 
 #include "base/macros.h"
-#include "components/mus/public/cpp/view_observer.h"
+#include "components/mus/public/cpp/window_observer.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/events/event_source.h"
 #include "ui/gfx/geometry/rect.h"
@@ -27,9 +27,9 @@
 class SurfaceContextFactory;
 
 class WindowTreeHostMojo : public aura::WindowTreeHost,
-                           public mus::ViewObserver {
+                           public mus::WindowObserver {
  public:
-  WindowTreeHostMojo(mojo::Shell* shell, mus::View* view);
+  WindowTreeHostMojo(mojo::Shell* shell, mus::Window* window);
   ~WindowTreeHostMojo() override;
 
   const gfx::Rect& bounds() const { return bounds_; }
@@ -53,12 +53,12 @@
   void MoveCursorToNative(const gfx::Point& location) override;
   void OnCursorVisibilityChangedNative(bool show) override;
 
-  // mus::ViewObserver:
-  void OnViewBoundsChanged(mus::View* view,
-                           const mojo::Rect& old_bounds,
-                           const mojo::Rect& new_bounds) override;
+  // mus::WindowObserver:
+  void OnWindowBoundsChanged(mus::Window* window,
+                             const mojo::Rect& old_bounds,
+                             const mojo::Rect& new_bounds) override;
 
-  mus::View* view_;
+  mus::Window* window_;
 
   gfx::Rect bounds_;
 
diff --git a/ui/webui/resources/cr_elements/v1_0/network/cr_network_list.css b/ui/webui/resources/cr_elements/v1_0/network/cr_network_list.css
index b4d5de05..9d6293b 100644
--- a/ui/webui/resources/cr_elements/v1_0/network/cr_network_list.css
+++ b/ui/webui/resources/cr_elements/v1_0/network/cr_network_list.css
@@ -3,7 +3,6 @@
  * found in the LICENSE file. */
 
 #container {
-  border: 1px solid;
   max-height: 1000px;
   min-height: 50px;
   overflow-y: auto;
@@ -13,3 +12,7 @@
 #networkList {
   flex: 1;
 }
+
+cr-network-list-item:not(:last-of-type) {
+  border-bottom: 1px solid lightgrey;
+}
diff --git a/ui/webui/resources/cr_elements/v1_0/policy/compiled_resources.gyp b/ui/webui/resources/cr_elements/v1_0/policy/compiled_resources.gyp
index 801f44a..a8701111 100644
--- a/ui/webui/resources/cr_elements/v1_0/policy/compiled_resources.gyp
+++ b/ui/webui/resources/cr_elements/v1_0/policy/compiled_resources.gyp
@@ -4,13 +4,39 @@
 {
   'targets': [
     {
-      'target_name': 'cr_policy_indicator',
+      'target_name': 'cr_policy_indicator_behavior',
+      'variables': {
+        'depends': [
+          '../../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
+          '../../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
+        ],
+      },
+      'includes': ['../../../../../../third_party/closure_compiler/compile_js.gypi'],
+    },
+    {
+      'target_name': 'cr_policy_pref_behavior',
       'variables': {
         'depends': [
           '../../../../../../third_party/polymer/v1_0/components-chromium/iron-iconset-svg/iron-iconset-svg-extracted.js',
           '../../../../../../third_party/polymer/v1_0/components-chromium/iron-meta/iron-meta-extracted.js',
           '../../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
           '../../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
+          'cr_policy_indicator_behavior.js',
+        ],
+        'externs': [
+          '../../../../../../third_party/closure_compiler/externs/settings_private.js'
+        ],
+      },
+      'includes': ['../../../../../../third_party/closure_compiler/compile_js.gypi'],
+    },
+    {
+      'target_name': 'cr_policy_pref_indicator',
+      'variables': {
+        'depends': [
+          '../../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
+          '../../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
+          'cr_policy_indicator_behavior.js',
+          'cr_policy_pref_behavior.js',
         ],
         'externs': [
           '../../../../../../third_party/closure_compiler/externs/settings_private.js'
diff --git a/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator.html b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator.html
deleted file mode 100644
index ea2ead1..0000000
--- a/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/social-icons.html">
-
-<dom-module id="cr-policy-indicator">
-  <link rel="import" type="css" href="cr_policy_indicator.css">
-  <template>
-    <div class="layout horizontal">
-      <iron-icon id="indicator"
-          hidden$="[[!isIndicatorVisible_(indicatorType)]]"
-          icon="[[getIcon_(indicatorType)]]"
-          title$="[[getTooltipText_(indicatorType, pref, controllingUser)]]">
-      </iron-icon>
-    </div>
-  </template>
-  <script src="cr_policy_indicator.js"></script>
-</dom-module>
diff --git a/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator.js b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator.js
deleted file mode 100644
index d9248c5..0000000
--- a/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator.js
+++ /dev/null
@@ -1,151 +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.
-
-/**
- * @fileoverview Polymer element for indicating policies that apply to an
- * element controlling a settings preference.
- */
-
-var CrPolicyIndicator = {
-  /** @enum {string} */
-  Type: {
-    DEVICE_POLICY: 'devicePolicy',
-    EXTENSION: 'extension',
-    NONE: 'none',
-    OWNER: 'owner',
-    PRIMARY_USER: 'primary_user',
-    RECOMMENDED: 'recommended',
-    USER_POLICY: 'userPolicy',
-  },
-};
-
-(function() {
-
-/** @element cr-policy-indicator */
-Polymer({
-  is: 'cr-policy-indicator',
-
-  properties: {
-    /**
-     * Optional preference object associated with the indicator. Initialized to
-     * null so that computed functions will get called if this is never set.
-     * @type {?chrome.settingsPrivate.PrefObject}
-     */
-    pref: {type: Object, value: null},
-
-    /**
-     * Optional email of the user controlling the setting when the setting does
-     * not correspond to a pref (Chrome OS only). Only used when pref is null.
-     * Initialized to '' so that computed functions will get called if this is
-     * never set.
-     */
-    controllingUser: {type: String, value: ''},
-
-    /**
-     * Which indicator type to show (or NONE).
-     * @type {CrPolicyIndicator.Type}
-     */
-    indicatorType: {type: String, value: CrPolicyIndicator.Type.NONE},
-  },
-
-  observers: ['prefPolicyChanged_(pref.policySource, pref.policyEnforcement)'],
-
-  /**
-   * Polymer observer for pref.
-   * @param {chrome.settingsPrivate.PolicySource} source
-   * @param {chrome.settingsPrivate.PolicyEnforcement} enforcement
-   * @private
-   */
-  prefPolicyChanged_: function(source, enforcement) {
-    var type = CrPolicyIndicator.Type.NONE;
-    if (enforcement == chrome.settingsPrivate.PolicyEnforcement.ENFORCED) {
-      if (source == chrome.settingsPrivate.PolicySource.PRIMARY_USER)
-        type = CrPolicyIndicator.Type.PRIMARY_USER;
-      else if (source == chrome.settingsPrivate.PolicySource.OWNER)
-        type = CrPolicyIndicator.Type.OWNER;
-      else if (source == chrome.settingsPrivate.PolicySource.USER_POLICY)
-        type = CrPolicyIndicator.Type.USER_POLICY;
-      else if (source == chrome.settingsPrivate.PolicySource.DEVICE_POLICY)
-        type = CrPolicyIndicator.Type.DEVICE_POLICY;
-      else if (source == chrome.settingsPrivate.PolicySource.EXTENSION)
-        type = CrPolicyIndicator.Type.EXTENSION;
-    } else if (enforcement ==
-               chrome.settingsPrivate.PolicyEnforcement.RECOMMENDED) {
-      type = CrPolicyIndicator.Type.RECOMMENDED;
-    }
-    this.indicatorType = type;
-  },
-
-  /**
-   * @param {CrPolicyIndicator.Type} type
-   * @return {boolean} True if the indicator should be shown.
-   * @private
-   */
-  isIndicatorVisible_: function(type) {
-    return type != CrPolicyIndicator.Type.NONE;
-  },
-
-  /**
-   * @param {CrPolicyIndicator.Type} type
-   * @return {string} The iron-icons icon name.
-   * @private
-   */
-  getIcon_: function(type) {
-    switch (type) {
-      case CrPolicyIndicator.Type.NONE:
-        return '';
-      case CrPolicyIndicator.Type.PRIMARY_USER:
-        return 'social:group';
-      case CrPolicyIndicator.Type.OWNER:
-        return 'social:person';
-      case CrPolicyIndicator.Type.USER_POLICY:
-      case CrPolicyIndicator.Type.DEVICE_POLICY:
-        return 'social:domain';
-      case CrPolicyIndicator.Type.EXTENSION:
-        return 'extension';
-      case CrPolicyIndicator.Type.RECOMMENDED:
-        return 'social:domain';
-    }
-    assertNotReached();
-  },
-
-  /**
-   * @param {string} id The id of the string to translate.
-   * @param {string=} opt_name An optional name argument.
-   * @return The translated string.
-   */
-  i18n_: function (id, opt_name) {
-    return loadTimeData.getStringF(id, opt_name);
-  },
-
-  /**
-   * @param {CrPolicyIndicator.Type} type The type of indicator.
-   * @param {?chrome.settingsPrivate.PrefObject} pref
-   * @param {string} controllingUser The user controlling the setting, if |pref|
-   *     is null.
-   * @return {string} The tooltip text for |type|.
-   * @private
-   */
-  getTooltipText_: function(type, pref, controllingUser) {
-    var name = pref ? pref.policySourceName : controllingUser;
-
-    switch (type) {
-      case CrPolicyIndicator.Type.PRIMARY_USER:
-        return this.i18n_('controlledSettingShared', name);
-      case CrPolicyIndicator.Type.OWNER:
-        return this.i18n_('controlledSettingOwner', name);
-      case CrPolicyIndicator.Type.USER_POLICY:
-      case CrPolicyIndicator.Type.DEVICE_POLICY:
-        return this.i18n_('controlledSettingPolicy');
-      case CrPolicyIndicator.Type.EXTENSION:
-        return this.i18n_('controlledSettingExtension', name);
-      case CrPolicyIndicator.Type.RECOMMENDED:
-        if (pref && pref.value == pref.recommendedValue)
-          return this.i18n_('controlledSettingRecommendedMatches');
-        return this.i18n_('controlledSettingRecommendedDiffers');
-    }
-    return '';
-  }
-});
-})();
diff --git a/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator_behavior.html b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator_behavior.html
new file mode 100644
index 0000000..518e6c1
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator_behavior.html
@@ -0,0 +1 @@
+<script src="cr_policy_indicator_behavior.js"></script>
diff --git a/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator_behavior.js b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator_behavior.js
new file mode 100644
index 0000000..dc474f0a
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_indicator_behavior.js
@@ -0,0 +1,89 @@
+// 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.
+
+/**
+ * @fileoverview Behavior for policy controlled indicators.
+ */
+
+/** @enum {string} */
+var CrPolicyIndicatorType = {
+  DEVICE_POLICY: 'devicePolicy',
+  EXTENSION: 'extension',
+  NONE: 'none',
+  OWNER: 'owner',
+  PRIMARY_USER: 'primary_user',
+  RECOMMENDED: 'recommended',
+  USER_POLICY: 'userPolicy',
+};
+
+/** @polymerBehavior */
+var CrPolicyIndicatorBehavior = {
+  /**
+   * @param {CrPolicyIndicatorType} type
+   * @return {boolean} True if the indicator should be shown.
+   * @private
+   */
+  isIndicatorVisible: function(type) {
+    return type != CrPolicyIndicatorType.NONE;
+  },
+
+  /**
+   * @param {CrPolicyIndicatorType} type
+   * @return {string} The iron-icons icon name.
+   * @private
+   */
+  getPolicyIndicatorIcon: function(type) {
+    switch (type) {
+      case CrPolicyIndicatorType.NONE:
+        return '';
+      case CrPolicyIndicatorType.PRIMARY_USER:
+        return 'social:group';
+      case CrPolicyIndicatorType.OWNER:
+        return 'social:person';
+      case CrPolicyIndicatorType.USER_POLICY:
+      case CrPolicyIndicatorType.DEVICE_POLICY:
+        return 'social:domain';
+      case CrPolicyIndicatorType.EXTENSION:
+        return 'extension';
+      case CrPolicyIndicatorType.RECOMMENDED:
+        return 'social:domain';
+    }
+    assertNotReached();
+    return '';
+  },
+
+  /**
+   * @param {string} id The id of the string to translate.
+   * @param {string=} opt_name An optional name argument.
+   * @return The translated string.
+   */
+  i18n_: function (id, opt_name) {
+    return loadTimeData.getStringF(id, opt_name);
+  },
+
+  /**
+   * @param {CrPolicyIndicatorType} type
+   * @param {string} name The name associated with the controllable. See
+   *     chrome.settingsPrivate.PrefObject.policySourceName
+   * @return {string} The tooltip text for |type|.
+   */
+  getPolicyIndicatorTooltip: function(type, name) {
+    switch (type) {
+      case CrPolicyIndicatorType.PRIMARY_USER:
+        return this.i18n_('controlledSettingShared', name);
+      case CrPolicyIndicatorType.OWNER:
+        return this.i18n_('controlledSettingOwner', name);
+      case CrPolicyIndicatorType.USER_POLICY:
+      case CrPolicyIndicatorType.DEVICE_POLICY:
+        return this.i18n_('controlledSettingPolicy');
+      case CrPolicyIndicatorType.EXTENSION:
+        return this.i18n_('controlledSettingExtension', name);
+      case CrPolicyIndicatorType.RECOMMENDED:
+        // This case is not handled here since it requires knowledge of the
+        // value and recommended value associated with the controllable.
+        assertNotReached();
+    }
+    return '';
+  }
+};
diff --git a/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_behavior.html b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_behavior.html
new file mode 100644
index 0000000..ab7bc58
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_behavior.html
@@ -0,0 +1 @@
+<script src="cr_policy_pref_behavior.js"></script>
diff --git a/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_behavior.js b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_behavior.js
new file mode 100644
index 0000000..d8897da6
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_behavior.js
@@ -0,0 +1,45 @@
+// 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.
+
+/**
+ * @fileoverview Behavior for policy controlled settings prefs.
+ */
+
+/** @polymerBehavior */
+var CrPolicyPrefBehavior = {
+  /**
+   * @param {!chrome.settingsPrivate.PrefObject} pref
+   * @return {boolean} True if the pref is controlled by an enforced policy.
+   */
+  isPrefPolicyControlled: function(pref) {
+    return pref.policyEnforcement ==
+           chrome.settingsPrivate.PolicyEnforcement.ENFORCED;
+  },
+
+  /**
+   * @param {chrome.settingsPrivate.PolicySource} source
+   * @param {chrome.settingsPrivate.PolicyEnforcement} enforcement
+   * @return {CrPolicyIndicatorType} The indicator type based on |source| and
+   *     |enforcement|.
+   */
+  getIndicatorType: function(source, enforcement) {
+    if (enforcement == chrome.settingsPrivate.PolicyEnforcement.RECOMMENDED)
+      return CrPolicyIndicatorType.RECOMMENDED;
+    if (enforcement == chrome.settingsPrivate.PolicyEnforcement.ENFORCED) {
+      switch (source) {
+        case chrome.settingsPrivate.PolicySource.PRIMARY_USER:
+          return CrPolicyIndicatorType.PRIMARY_USER;
+        case chrome.settingsPrivate.PolicySource.OWNER:
+          return CrPolicyIndicatorType.OWNER;
+        case chrome.settingsPrivate.PolicySource.USER_POLICY:
+          return CrPolicyIndicatorType.USER_POLICY;
+        case chrome.settingsPrivate.PolicySource.DEVICE_POLICY:
+          return CrPolicyIndicatorType.DEVICE_POLICY;
+        case chrome.settingsPrivate.PolicySource.EXTENSION:
+          return CrPolicyIndicatorType.EXTENSION;
+      }
+    }
+    return CrPolicyIndicatorType.NONE;
+  },
+};
diff --git a/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_indicator.html b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_indicator.html
new file mode 100644
index 0000000..56bc23d1
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_indicator.html
@@ -0,0 +1,20 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/social-icons.html">
+<link rel="import" href="cr_policy_indicator_behavior.html">
+<link rel="import" href="cr_policy_pref_behavior.html">
+
+<dom-module id="cr-policy-pref-indicator">
+  <link rel="import" type="css" href="cr_policy_indicator.css">
+  <template>
+    <div class="layout horizontal">
+      <iron-icon id="indicator"
+          hidden$="[[!isIndicatorVisible(indicatorType)]]"
+          icon="[[getPolicyIndicatorIcon(indicatorType)]]"
+          title$="[[getPolicyIndicatorTooltip(indicatorType, pref, controllingUser)]]">
+      </iron-icon>
+    </div>
+  </template>
+  <script src="cr_policy_pref_indicator.js"></script>
+</dom-module>
diff --git a/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_indicator.js b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_indicator.js
new file mode 100644
index 0000000..769ba62f
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/policy/cr_policy_pref_indicator.js
@@ -0,0 +1,59 @@
+// 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.
+
+/**
+ * @fileoverview Polymer element for indicating policies that apply to an
+ * element controlling a settings preference.
+ *
+ * @element cr-policy-pref-indicator
+ */
+Polymer({
+  is: 'cr-policy-pref-indicator',
+
+  behaviors: [CrPolicyIndicatorBehavior, CrPolicyPrefBehavior],
+
+  properties: {
+    /**
+     * Optional preference object associated with the indicator. Initialized to
+     * null so that computed functions will get called if this is never set.
+     * @type {?chrome.settingsPrivate.PrefObject}
+     */
+    pref: {type: Object, value: null},
+
+    /**
+     * Optional email of the user controlling the setting when the setting does
+     * not correspond to a pref (Chrome OS only). Only used when pref is null.
+     * Initialized to '' so that computed functions will get called if this is
+     * never set. TODO(stevenjb/michaelpg): Create a separate indicator for
+     * non-pref (i.e. explicitly set) indicators (see languyage_detail_page).
+     */
+    controllingUser: {type: String, value: ''},
+
+    /**
+     * Which indicator type to show (or NONE).
+     * @type {CrPolicyIndicatorType}
+     */
+    indicatorType: {
+      type: String,
+      value: CrPolicyIndicatorType.NONE,
+      computed: 'getIndicatorType(pref.policySource, pref.policyEnforcement)',
+    },
+  },
+
+  /**
+   * @param {CrPolicyIndicatorType} type
+   * @param {?chrome.settingsPrivate.PrefObject} pref
+   * @return {string} The tooltip text for |type|.
+   * @private
+   */
+  getTooltip_: function(type, pref, controllingUser) {
+    if (type == CrPolicyIndicatorType.RECOMMENDED) {
+      if (pref && pref.value == pref.recommendedValue)
+        return this.i18n_('controlledSettingRecommendedMatches');
+      return this.i18n_('controlledSettingRecommendedDiffers');
+    }
+    var name = pref ? pref.policySourceName : controllingUser;
+    return this.getPolicyIndicatorTooltip(type, name);
+  }
+});
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp
index 6b781428..f687d82 100644
--- a/ui/webui/resources/cr_elements_resources.grdp
+++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -87,11 +87,23 @@
   <structure name="IDR_CR_ELEMENTS_1_0_CR_POLICY_INDICATOR_CSS"
              file="../../webui/resources/cr_elements/v1_0/policy/cr_policy_indicator.css"
              type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_1_0_CR_POLICY_INDICATOR_HTML"
-             file="../../webui/resources/cr_elements/v1_0/policy/cr_policy_indicator.html"
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_POLICY_INDICATOR_BEHAVIOR_HTML"
+             file="../../webui/resources/cr_elements/v1_0/policy/cr_policy_indicator_behavior.html"
              type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_1_0_CR_POLICY_INDICATOR_JS"
-             file="../../webui/resources/cr_elements/v1_0/policy/cr_policy_indicator.js"
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_POLICY_INDICATOR_BEHAVIOR_JS"
+             file="../../webui/resources/cr_elements/v1_0/policy/cr_policy_indicator_behavior.js"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_POLICY_PREF_BEHAVIOR_HTML"
+             file="../../webui/resources/cr_elements/v1_0/policy/cr_policy_pref_behavior.html"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_POLICY_PREF_BEHAVIOR_JS"
+             file="../../webui/resources/cr_elements/v1_0/policy/cr_policy_pref_behavior.js"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_POLICY_PREF_INDICATOR_JS"
+             file="../../webui/resources/cr_elements/v1_0/policy/cr_policy_pref_indicator.js"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_POLICY_PREF_INDICATOR_HTML"
+             file="../../webui/resources/cr_elements/v1_0/policy/cr_policy_pref_indicator.html"
              type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_1_0_CR_SEARCH_FIELD_CSS"
              file="../../webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.css"
diff --git a/ui/webui/resources/css/roboto.css b/ui/webui/resources/css/roboto.css
index 776fa92..34c0ad7 100644
--- a/ui/webui/resources/css/roboto.css
+++ b/ui/webui/resources/css/roboto.css
@@ -7,9 +7,7 @@
   font-style: normal;
   font-weight: 400;
   src: local('Roboto'), local('Roboto-Regular'),
-      url(chrome://resources/roboto/roboto-regular-latin.woff2) format('woff2');
-  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
-      U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
+      url(chrome://resources/roboto/roboto-regular.woff2) format('woff2');
 }
 
 @font-face {
@@ -17,7 +15,5 @@
   font-style: normal;
   font-weight: 500;
   src: local('Roboto Medium'), local('Roboto-Medium'),
-      url(chrome://resources/roboto/roboto-medium-latin.woff2) format('woff2');
-  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
-      U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
+      url(chrome://resources/roboto/roboto-medium.woff2) format('woff2');
 }
diff --git a/ui/webui/resources/js/cr/ui/table.js b/ui/webui/resources/js/cr/ui/table.js
index 6a2640086..3e7b301 100644
--- a/ui/webui/resources/js/cr/ui/table.js
+++ b/ui/webui/resources/js/cr/ui/table.js
@@ -218,7 +218,6 @@
     /**
      * Ensures that a given index is inside the viewport.
      * @param {number} i The index of the item to scroll into view.
-     * @return {boolean} Whether any scrolling was needed.
      */
     scrollIndexIntoView: function(i) {
       this.list_.scrollIndexIntoView(i);
diff --git a/ui/webui/resources/roboto/roboto-medium-latin.woff2 b/ui/webui/resources/roboto/roboto-medium-latin.woff2
deleted file mode 100644
index 5f96609d..0000000
--- a/ui/webui/resources/roboto/roboto-medium-latin.woff2
+++ /dev/null
Binary files differ
diff --git a/ui/webui/resources/roboto/roboto-medium.woff2 b/ui/webui/resources/roboto/roboto-medium.woff2
new file mode 100644
index 0000000..ad8f5bc
--- /dev/null
+++ b/ui/webui/resources/roboto/roboto-medium.woff2
Binary files differ
diff --git a/ui/webui/resources/roboto/roboto-regular-latin.woff2 b/ui/webui/resources/roboto/roboto-regular-latin.woff2
deleted file mode 100644
index 120796b..0000000
--- a/ui/webui/resources/roboto/roboto-regular-latin.woff2
+++ /dev/null
Binary files differ
diff --git a/ui/webui/resources/roboto/roboto-regular.woff2 b/ui/webui/resources/roboto/roboto-regular.woff2
new file mode 100644
index 0000000..bf6ecad
--- /dev/null
+++ b/ui/webui/resources/roboto/roboto-regular.woff2
Binary files differ
diff --git a/ui/webui/resources/webui_resources.grd b/ui/webui/resources/webui_resources.grd
index 50af42a..fa62cbd 100644
--- a/ui/webui/resources/webui_resources.grd
+++ b/ui/webui/resources/webui_resources.grd
@@ -16,9 +16,12 @@
       <include name="IDR_WEBUI_I18N_TEMPLATE_JS" file="js/i18n_template.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_WEBUI_JSTEMPLATE_JS" file="js/jstemplate_compiled.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_WEBUI_ANALYTICS_JS" file="js/analytics.js" flattenhtml="true" type="BINDATA" />
-      <!-- Roboto Font -->
-      <include name="IDR_WEBUI_ROBOTO_ROBOTO_REGULAR_LATIN_WOFF2" file="roboto/roboto-regular-latin.woff2" type="BINDATA" />
-      <include name="IDR_WEBUI_ROBOTO_ROBOTO_MEDIUM_LATIN_WOFF2" file="roboto/roboto-medium-latin.woff2" type="BINDATA" />
+      <!-- Roboto Font. Roboto-Regular is already available on Android, and
+        Roboto-Medium is not used on Android. -->
+      <if expr="not android">
+        <include name="IDR_WEBUI_ROBOTO_ROBOTO_REGULAR_WOFF2" file="roboto/roboto-regular.woff2" type="BINDATA" />
+        <include name="IDR_WEBUI_ROBOTO_ROBOTO_MEDIUM_WOFF2" file="roboto/roboto-medium.woff2" type="BINDATA" />
+      </if>
 
       <!-- Component apps common image resources - 1x -->
       <!-- White button -->