Reify view ownership as a message pipe.

This patch changes the View Manager API to allow for pipelined
creation and addition of views into the view hierarchy using a
new |ViewOwner| object to mediate the transfer of ownership
between clients.

The ownership model ensures that views always belong either to
a view hierarchy (as a child of some other view or as the root
of a view tree) or to a |ViewOwner| in transit.

Previously, it was more difficult to reason about the lifetime
of views since the |ViewToken| afforded no way to track ownership
transfer and therefore lifetime had to be negotiated out-of-band
by applications themselves (a fact which was not adequately captured
by the |ViewProvider| mechanism or example programs).

Bug #654

BUG=
R=abarth@google.com

Review URL: https://codereview.chromium.org/1679023006 .
diff --git a/apps/moterm/moterm_app.cc b/apps/moterm/moterm_app.cc
index efdb0fa..e8d2e2d 100644
--- a/apps/moterm/moterm_app.cc
+++ b/apps/moterm/moterm_app.cc
@@ -10,11 +10,10 @@
 
 MotermApp::~MotermApp() {}
 
-bool MotermApp::CreateView(
+void MotermApp::CreateView(
     const std::string& connection_url,
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
     mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services,
-    const mojo::ui::ViewProvider::CreateViewCallback& callback) {
-  new MotermView(app_impl(), services.Pass(), callback);
-  return true;
+    mojo::ServiceProviderPtr exposed_services) {
+  new MotermView(app_impl(), view_owner_request.Pass(), services.Pass());
 }
diff --git a/apps/moterm/moterm_app.h b/apps/moterm/moterm_app.h
index 0b4aead..7ff9f68 100644
--- a/apps/moterm/moterm_app.h
+++ b/apps/moterm/moterm_app.h
@@ -13,11 +13,11 @@
   MotermApp();
   ~MotermApp() override;
 
-  bool CreateView(
+  void CreateView(
       const std::string& connection_url,
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
       mojo::InterfaceRequest<mojo::ServiceProvider> services,
-      mojo::ServiceProviderPtr exposed_services,
-      const mojo::ui::ViewProvider::CreateViewCallback& callback) override;
+      mojo::ServiceProviderPtr exposed_services) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MotermApp);
diff --git a/apps/moterm/moterm_view.cc b/apps/moterm/moterm_view.cc
index 4f992cc..30b8e94 100644
--- a/apps/moterm/moterm_view.cc
+++ b/apps/moterm/moterm_view.cc
@@ -38,9 +38,9 @@
 
 MotermView::MotermView(
     mojo::ApplicationImpl* app_impl,
-    mojo::InterfaceRequest<mojo::ServiceProvider> service_provider_request,
-    const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback)
-    : GaneshView(app_impl, "Moterm", create_view_callback),
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+    mojo::InterfaceRequest<mojo::ServiceProvider> service_provider_request)
+    : GaneshView(app_impl, view_owner_request.Pass(), "Moterm"),
       choreographer_(scene(), this),
       input_handler_(view_service_provider(), this),
       model_(MotermModel::Size(240, 160), MotermModel::Size(24, 80), this),
diff --git a/apps/moterm/moterm_view.h b/apps/moterm/moterm_view.h
index 4569f3d..06c319b 100644
--- a/apps/moterm/moterm_view.h
+++ b/apps/moterm/moterm_view.h
@@ -35,8 +35,8 @@
  public:
   MotermView(
       mojo::ApplicationImpl* app_impl,
-      mojo::InterfaceRequest<mojo::ServiceProvider> service_provider_request,
-      const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback);
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+      mojo::InterfaceRequest<mojo::ServiceProvider> service_provider_request);
   ~MotermView() override;
 
  private:
diff --git a/examples/moterm_example_app/BUILD.gn b/examples/moterm_example_app/BUILD.gn
index dc3701d..007ad07 100644
--- a/examples/moterm_example_app/BUILD.gn
+++ b/examples/moterm_example_app/BUILD.gn
@@ -20,5 +20,6 @@
     "//mojo/services/geometry/interfaces",
     "//mojo/services/terminal/interfaces",
     "//mojo/services/ui/views/interfaces",
+    "//mojo/ui",
   ]
 }
diff --git a/examples/moterm_example_app/moterm_example_app.cc b/examples/moterm_example_app/moterm_example_app.cc
index edab7ac..e6364fc 100644
--- a/examples/moterm_example_app/moterm_example_app.cc
+++ b/examples/moterm_example_app/moterm_example_app.cc
@@ -32,6 +32,7 @@
 #include "mojo/services/ui/views/interfaces/view_manager.mojom.h"
 #include "mojo/services/ui/views/interfaces/view_provider.mojom.h"
 #include "mojo/services/ui/views/interfaces/views.mojom.h"
+#include "mojo/ui/view_provider_app.h"
 
 // Kind of like |fputs()| (doesn't wait for result).
 void Fputs(mojo::files::File* file, const char* s) {
@@ -47,7 +48,7 @@
  public:
   MotermExampleAppView(
       mojo::Shell* shell,
-      const mojo::ui::ViewProvider::CreateViewCallback& callback)
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request)
       : shell_(shell), weak_factory_(this) {
     // Connect to the moterm app.
     LOG(INFO) << "Connecting to moterm";
@@ -57,8 +58,8 @@
     // Create the moterm view and pass it back to the client directly.
     mojo::ConnectToService(moterm_app.get(), &moterm_view_provider_);
     mojo::ServiceProviderPtr moterm_service_provider;
-    moterm_view_provider_->CreateView(GetProxy(&moterm_service_provider),
-                                      nullptr, callback);
+    moterm_view_provider_->CreateView(
+        view_owner_request.Pass(), GetProxy(&moterm_service_provider), nullptr);
 
     // Connect to the moterm terminal service associated with the view
     // we just created.
@@ -154,42 +155,21 @@
   DISALLOW_COPY_AND_ASSIGN(MotermExampleAppView);
 };
 
-class MotermExampleApp : public mojo::ApplicationDelegate,
-                         public mojo::InterfaceFactory<mojo::ui::ViewProvider>,
-                         public mojo::ui::ViewProvider {
+class MotermExampleApp : public mojo::ui::ViewProviderApp {
  public:
-  MotermExampleApp() : application_impl_() {}
+  MotermExampleApp() {}
   ~MotermExampleApp() override {}
 
+  // |ViewProviderApp|:
+  void CreateView(
+      const std::string& connection_url,
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+      mojo::InterfaceRequest<mojo::ServiceProvider> services,
+      mojo::ServiceProviderPtr exposed_services) override {
+    new MotermExampleAppView(app_impl()->shell(), view_owner_request.Pass());
+  }
+
  private:
-  // |mojo::ApplicationDelegate|:
-  void Initialize(mojo::ApplicationImpl* application_impl) override {
-    DCHECK(!application_impl_);
-    application_impl_ = application_impl;
-  }
-
-  bool ConfigureIncomingConnection(
-      mojo::ApplicationConnection* connection) override {
-    connection->AddService<mojo::ui::ViewProvider>(this);
-    return true;
-  }
-
-  // |InterfaceFactory<mojo::ui::ViewProvider>|:
-  void Create(mojo::ApplicationConnection* connection,
-              mojo::InterfaceRequest<mojo::ui::ViewProvider> request) override {
-    bindings_.AddBinding(this, request.Pass());
-  }
-
-  // |ViewProvider|:
-  void CreateView(mojo::InterfaceRequest<mojo::ServiceProvider> services,
-                  mojo::ServiceProviderPtr exposed_services,
-                  const CreateViewCallback& callback) override {
-    new MotermExampleAppView(application_impl_->shell(), callback);
-  }
-
-  mojo::ApplicationImpl* application_impl_;
-  mojo::BindingSet<mojo::ui::ViewProvider> bindings_;
-
   DISALLOW_COPY_AND_ASSIGN(MotermExampleApp);
 };
 
diff --git a/examples/ui/noodles/noodles_app.cc b/examples/ui/noodles/noodles_app.cc
index 31a3c4c..4a6543d 100644
--- a/examples/ui/noodles/noodles_app.cc
+++ b/examples/ui/noodles/noodles_app.cc
@@ -12,13 +12,12 @@
 
 NoodlesApp::~NoodlesApp() {}
 
-bool NoodlesApp::CreateView(
+void NoodlesApp::CreateView(
     const std::string& connection_url,
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
     mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services,
-    const mojo::ui::ViewProvider::CreateViewCallback& callback) {
-  new NoodlesView(app_impl(), callback);
-  return true;
+    mojo::ServiceProviderPtr exposed_services) {
+  new NoodlesView(app_impl(), view_owner_request.Pass());
 }
 
 }  // namespace examples
diff --git a/examples/ui/noodles/noodles_app.h b/examples/ui/noodles/noodles_app.h
index 221cd8e..6556b2b 100644
--- a/examples/ui/noodles/noodles_app.h
+++ b/examples/ui/noodles/noodles_app.h
@@ -14,11 +14,11 @@
   NoodlesApp();
   ~NoodlesApp() override;
 
-  bool CreateView(
+  void CreateView(
       const std::string& connection_url,
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
       mojo::InterfaceRequest<mojo::ServiceProvider> services,
-      mojo::ServiceProviderPtr exposed_services,
-      const mojo::ui::ViewProvider::CreateViewCallback& callback) override;
+      mojo::ServiceProviderPtr exposed_services) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(NoodlesApp);
diff --git a/examples/ui/noodles/noodles_view.cc b/examples/ui/noodles/noodles_view.cc
index 921e00a..ad85ded 100644
--- a/examples/ui/noodles/noodles_view.cc
+++ b/examples/ui/noodles/noodles_view.cc
@@ -50,8 +50,8 @@
 
 NoodlesView::NoodlesView(
     mojo::ApplicationImpl* app_impl,
-    const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback)
-    : BaseView(app_impl, "Noodles", create_view_callback),
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request)
+    : BaseView(app_impl, view_owner_request.Pass(), "Noodles"),
       choreographer_(scene(), this),
       frame_queue_(std::make_shared<FrameQueue>()),
       rasterizer_delegate_(
diff --git a/examples/ui/noodles/noodles_view.h b/examples/ui/noodles/noodles_view.h
index f64ec53..adc01c8 100644
--- a/examples/ui/noodles/noodles_view.h
+++ b/examples/ui/noodles/noodles_view.h
@@ -27,9 +27,8 @@
 class NoodlesView : public mojo::ui::BaseView,
                     public mojo::ui::ChoreographerDelegate {
  public:
-  NoodlesView(
-      mojo::ApplicationImpl* app_impl,
-      const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback);
+  NoodlesView(mojo::ApplicationImpl* app_impl,
+              mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request);
 
   ~NoodlesView() override;
 
diff --git a/examples/ui/pdf_viewer/pdf_viewer.cc b/examples/ui/pdf_viewer/pdf_viewer.cc
index ee760ab..ce5c605 100644
--- a/examples/ui/pdf_viewer/pdf_viewer.cc
+++ b/examples/ui/pdf_viewer/pdf_viewer.cc
@@ -117,9 +117,9 @@
  public:
   PDFDocumentView(
       mojo::ApplicationImpl* app_impl,
-      const std::shared_ptr<PDFDocument>& pdf_document,
-      const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback)
-      : GaneshView(app_impl, "PDFDocumentViewer", create_view_callback),
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+      const std::shared_ptr<PDFDocument>& pdf_document)
+      : GaneshView(app_impl, view_owner_request.Pass(), "PDFDocumentViewer"),
         pdf_document_(pdf_document),
         choreographer_(scene(), this),
         input_handler_(view_service_provider(), this) {
@@ -256,13 +256,12 @@
 
   ~PDFContentViewProviderApp() override {}
 
-  bool CreateView(
+  void CreateView(
       const std::string& connection_url,
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
       mojo::InterfaceRequest<mojo::ServiceProvider> services,
-      mojo::ServiceProviderPtr exposed_services,
-      const mojo::ui::ViewProvider::CreateViewCallback& callback) override {
-    new PDFDocumentView(app_impl(), pdf_document_, callback);
-    return true;
+      mojo::ServiceProviderPtr exposed_services) override {
+    new PDFDocumentView(app_impl(), view_owner_request.Pass(), pdf_document_);
   }
 
  private:
diff --git a/examples/ui/png_viewer/png_viewer.cc b/examples/ui/png_viewer/png_viewer.cc
index abd5c48..16265e4 100644
--- a/examples/ui/png_viewer/png_viewer.cc
+++ b/examples/ui/png_viewer/png_viewer.cc
@@ -27,11 +27,11 @@
 
 class PNGView : public mojo::ui::GaneshView {
  public:
-  PNGView(
-      mojo::ApplicationImpl* app_impl,
-      const skia::RefPtr<SkImage>& image,
-      const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback)
-      : GaneshView(app_impl, "PNGViewer", create_view_callback), image_(image) {
+  PNGView(mojo::ApplicationImpl* app_impl,
+          mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+          const skia::RefPtr<SkImage>& image)
+      : GaneshView(app_impl, view_owner_request.Pass(), "PNGViewer"),
+        image_(image) {
     DCHECK(image_);
   }
 
@@ -106,13 +106,12 @@
 
   ~PNGContentViewProviderApp() override {}
 
-  bool CreateView(
+  void CreateView(
       const std::string& connection_url,
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
       mojo::InterfaceRequest<mojo::ServiceProvider> services,
-      mojo::ServiceProviderPtr exposed_services,
-      const mojo::ui::ViewProvider::CreateViewCallback& callback) override {
-    new PNGView(app_impl(), image_, callback);
-    return true;
+      mojo::ServiceProviderPtr exposed_services) override {
+    new PNGView(app_impl(), view_owner_request.Pass(), image_);
   }
 
  private:
diff --git a/examples/ui/shapes/shapes_app.cc b/examples/ui/shapes/shapes_app.cc
index 86443a1..917c274 100644
--- a/examples/ui/shapes/shapes_app.cc
+++ b/examples/ui/shapes/shapes_app.cc
@@ -12,13 +12,12 @@
 
 ShapesApp::~ShapesApp() {}
 
-bool ShapesApp::CreateView(
+void ShapesApp::CreateView(
     const std::string& connection_url,
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
     mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services,
-    const mojo::ui::ViewProvider::CreateViewCallback& callback) {
-  new ShapesView(app_impl(), callback);
-  return true;
+    mojo::ServiceProviderPtr exposed_services) {
+  new ShapesView(app_impl(), view_owner_request.Pass());
 }
 
 }  // namespace examples
diff --git a/examples/ui/shapes/shapes_app.h b/examples/ui/shapes/shapes_app.h
index 4aba71c..d44c2d7 100644
--- a/examples/ui/shapes/shapes_app.h
+++ b/examples/ui/shapes/shapes_app.h
@@ -14,11 +14,11 @@
   ShapesApp();
   ~ShapesApp() override;
 
-  bool CreateView(
+  void CreateView(
       const std::string& connection_url,
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
       mojo::InterfaceRequest<mojo::ServiceProvider> services,
-      mojo::ServiceProviderPtr exposed_services,
-      const mojo::ui::ViewProvider::CreateViewCallback& callback) override;
+      mojo::ServiceProviderPtr exposed_services) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ShapesApp);
diff --git a/examples/ui/shapes/shapes_view.cc b/examples/ui/shapes/shapes_view.cc
index 8bea9c3..1a6803b 100644
--- a/examples/ui/shapes/shapes_view.cc
+++ b/examples/ui/shapes/shapes_view.cc
@@ -19,8 +19,8 @@
 
 ShapesView::ShapesView(
     mojo::ApplicationImpl* app_impl,
-    const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback)
-    : GaneshView(app_impl, "Shapes", create_view_callback) {}
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request)
+    : GaneshView(app_impl, view_owner_request.Pass(), "Shapes") {}
 
 ShapesView::~ShapesView() {}
 
diff --git a/examples/ui/shapes/shapes_view.h b/examples/ui/shapes/shapes_view.h
index d041f7e..fb53987 100644
--- a/examples/ui/shapes/shapes_view.h
+++ b/examples/ui/shapes/shapes_view.h
@@ -13,9 +13,8 @@
 
 class ShapesView : public mojo::ui::GaneshView {
  public:
-  ShapesView(
-      mojo::ApplicationImpl* app_impl,
-      const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback);
+  ShapesView(mojo::ApplicationImpl* app_impl,
+             mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request);
 
   ~ShapesView() override;
 
diff --git a/examples/ui/spinning_cube/spinning_cube_app.cc b/examples/ui/spinning_cube/spinning_cube_app.cc
index 79818ee..8c1d797 100644
--- a/examples/ui/spinning_cube/spinning_cube_app.cc
+++ b/examples/ui/spinning_cube/spinning_cube_app.cc
@@ -12,13 +12,12 @@
 
 SpinningCubeApp::~SpinningCubeApp() {}
 
-bool SpinningCubeApp::CreateView(
+void SpinningCubeApp::CreateView(
     const std::string& connection_url,
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
     mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services,
-    const mojo::ui::ViewProvider::CreateViewCallback& callback) {
-  new SpinningCubeView(app_impl(), callback);
-  return true;
+    mojo::ServiceProviderPtr exposed_services) {
+  new SpinningCubeView(app_impl(), view_owner_request.Pass());
 }
 
 }  // namespace examples
diff --git a/examples/ui/spinning_cube/spinning_cube_app.h b/examples/ui/spinning_cube/spinning_cube_app.h
index e658717..5aa3f5f 100644
--- a/examples/ui/spinning_cube/spinning_cube_app.h
+++ b/examples/ui/spinning_cube/spinning_cube_app.h
@@ -14,11 +14,11 @@
   SpinningCubeApp();
   ~SpinningCubeApp() override;
 
-  bool CreateView(
+  void CreateView(
       const std::string& connection_url,
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
       mojo::InterfaceRequest<mojo::ServiceProvider> services,
-      mojo::ServiceProviderPtr exposed_services,
-      const mojo::ui::ViewProvider::CreateViewCallback& callback) override;
+      mojo::ServiceProviderPtr exposed_services) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SpinningCubeApp);
diff --git a/examples/ui/spinning_cube/spinning_cube_view.cc b/examples/ui/spinning_cube/spinning_cube_view.cc
index 68fb4f6..294d328 100644
--- a/examples/ui/spinning_cube/spinning_cube_view.cc
+++ b/examples/ui/spinning_cube/spinning_cube_view.cc
@@ -54,8 +54,8 @@
 
 SpinningCubeView::SpinningCubeView(
     mojo::ApplicationImpl* app_impl,
-    const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback)
-    : GLView(app_impl, "SpinningCube", create_view_callback),
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request)
+    : GLView(app_impl, view_owner_request.Pass(), "SpinningCube"),
       choreographer_(scene(), this),
       input_handler_(view_service_provider(), this),
       weak_ptr_factory_(this) {
diff --git a/examples/ui/spinning_cube/spinning_cube_view.h b/examples/ui/spinning_cube/spinning_cube_view.h
index e65220c..7ef4d3f 100644
--- a/examples/ui/spinning_cube/spinning_cube_view.h
+++ b/examples/ui/spinning_cube/spinning_cube_view.h
@@ -20,7 +20,7 @@
  public:
   SpinningCubeView(
       mojo::ApplicationImpl* app_impl,
-      const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback);
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request);
 
   ~SpinningCubeView() override;
 
diff --git a/examples/ui/tile/tile_app.cc b/examples/ui/tile/tile_app.cc
index 2f5d4a4..fcec7c6 100644
--- a/examples/ui/tile/tile_app.cc
+++ b/examples/ui/tile/tile_app.cc
@@ -15,11 +15,11 @@
 
 TileApp::~TileApp() {}
 
-bool TileApp::CreateView(
+void TileApp::CreateView(
     const std::string& connection_url,
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
     mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services,
-    const mojo::ui::ViewProvider::CreateViewCallback& callback) {
+    mojo::ServiceProviderPtr exposed_services) {
   GURL url(connection_url);
   std::vector<std::string> view_urls;
   base::SplitString(url.query(), ',', &view_urls);
@@ -27,11 +27,10 @@
   if (view_urls.empty()) {
     LOG(ERROR) << "Must supply comma-delimited URLs of mojo views to tile as a "
                   "query parameter.";
-    return false;
+    return;
   }
 
-  new TileView(app_impl(), view_urls, callback);
-  return true;
+  new TileView(app_impl(), view_owner_request.Pass(), view_urls);
 }
 
 }  // namespace examples
diff --git a/examples/ui/tile/tile_app.h b/examples/ui/tile/tile_app.h
index 1b4d619..35ba767 100644
--- a/examples/ui/tile/tile_app.h
+++ b/examples/ui/tile/tile_app.h
@@ -14,11 +14,11 @@
   TileApp();
   ~TileApp() override;
 
-  bool CreateView(
+  void CreateView(
       const std::string& connection_url,
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
       mojo::InterfaceRequest<mojo::ServiceProvider> services,
-      mojo::ServiceProviderPtr exposed_services,
-      const mojo::ui::ViewProvider::CreateViewCallback& callback) override;
+      mojo::ServiceProviderPtr exposed_services) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TileApp);
diff --git a/examples/ui/tile/tile_view.cc b/examples/ui/tile/tile_view.cc
index 744f9c4..a5fb1e8 100644
--- a/examples/ui/tile/tile_view.cc
+++ b/examples/ui/tile/tile_view.cc
@@ -19,10 +19,12 @@
 constexpr uint32_t kViewFallbackNodeIdOffset = 2;
 }  // namespace
 
-TileView::TileView(mojo::ApplicationImpl* app_impl,
-                   const std::vector<std::string>& view_urls,
-                   const mojo::ui::ViewProvider::CreateViewCallback& callback)
-    : BaseView(app_impl, "Tile", callback), view_urls_(view_urls) {
+TileView::TileView(
+    mojo::ApplicationImpl* app_impl,
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+    const std::vector<std::string>& view_urls)
+    : BaseView(app_impl, view_owner_request.Pass(), "Tile"),
+      view_urls_(view_urls) {
   ConnectViews();
 }
 
@@ -34,44 +36,20 @@
     // Start connecting to the view provider.
     mojo::ui::ViewProviderPtr provider;
     app_impl()->ConnectToService(url, &provider);
-    provider.set_connection_error_handler(
-        base::Bind(&TileView::OnChildConnectionError, base::Unretained(this),
-                   child_key, url));
 
-    // Create the view.
-    // We include the provider reference in the callback so that the
-    // binding will be kept alive until the callback completes.
     LOG(INFO) << "Connecting to view: child_key=" << child_key
               << ", url=" << url;
-    provider->CreateView(
-        nullptr, nullptr,
-        base::Bind(&TileView::OnChildCreated, base::Unretained(this), child_key,
-                   url, base::Passed(provider.Pass())));
+    mojo::ui::ViewOwnerPtr child_view_owner;
+    provider->CreateView(mojo::GetProxy(&child_view_owner), nullptr, nullptr);
+
+    view_host()->AddChild(child_key, child_view_owner.Pass());
+    views_.emplace(std::make_pair(
+        child_key, std::unique_ptr<ViewData>(new ViewData(url, child_key))));
+
     child_key++;
   }
 }
 
-void TileView::OnChildConnectionError(uint32_t child_key,
-                                      const std::string& url) {
-  LOG(ERROR) << "Could not connect to view: child_key=" << child_key
-             << ", url=" << url;
-}
-
-void TileView::OnChildCreated(uint32_t child_key,
-                              const std::string& url,
-                              mojo::ui::ViewProviderPtr provider,
-                              mojo::ui::ViewTokenPtr token) {
-  DCHECK(views_.find(child_key) == views_.end());
-  LOG(INFO) << "View created: child_key=" << child_key << ", url=" << url;
-
-  view_host()->AddChild(child_key, token.Pass());
-  views_.emplace(std::make_pair(
-      child_key, std::unique_ptr<ViewData>(new ViewData(url, child_key))));
-
-  // Note that the view provider will be destroyed once this function
-  // returns which is fine now that we are done creating the view.
-}
-
 void TileView::OnChildUnavailable(uint32_t child_key,
                                   const OnChildUnavailableCallback& callback) {
   auto it = views_.find(child_key);
@@ -82,7 +60,7 @@
   std::unique_ptr<ViewData> view_data = std::move(it->second);
   views_.erase(it);
 
-  view_host()->RemoveChild(child_key);
+  view_host()->RemoveChild(child_key, nullptr);
 
   if (view_data->layout_pending) {
     DCHECK(pending_child_layout_count_);
diff --git a/examples/ui/tile/tile_view.h b/examples/ui/tile/tile_view.h
index 085e431..85f4b85 100644
--- a/examples/ui/tile/tile_view.h
+++ b/examples/ui/tile/tile_view.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <memory>
 
+#include "mojo/services/ui/views/interfaces/view_provider.mojom.h"
 #include "mojo/ui/base_view.h"
 
 namespace examples {
@@ -15,8 +16,8 @@
 class TileView : public mojo::ui::BaseView {
  public:
   TileView(mojo::ApplicationImpl* app_impl_,
-           const std::vector<std::string>& view_urls,
-           const mojo::ui::ViewProvider::CreateViewCallback& callback);
+           mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+           const std::vector<std::string>& view_urls);
 
   ~TileView() override;
 
@@ -42,11 +43,6 @@
                           const OnChildUnavailableCallback& callback) override;
 
   void ConnectViews();
-  void OnChildConnectionError(uint32_t child_key, const std::string& url);
-  void OnChildCreated(uint32_t child_key,
-                      const std::string& url,
-                      mojo::ui::ViewProviderPtr provider,
-                      mojo::ui::ViewTokenPtr token);
   void OnChildLayoutFinished(uint32_t child_key,
                              mojo::ui::ViewLayoutInfoPtr child_layout_info);
   void FinishLayout();
diff --git a/mojo/dart/packages/mojo_services/lib/mojo/ui/view_manager.mojom.dart b/mojo/dart/packages/mojo_services/lib/mojo/ui/view_manager.mojom.dart
index f1d603a..6c95ce3 100644
--- a/mojo/dart/packages/mojo_services/lib/mojo/ui/view_manager.mojom.dart
+++ b/mojo/dart/packages/mojo_services/lib/mojo/ui/view_manager.mojom.dart
@@ -23,6 +23,7 @@
   ];
   Object view = null;
   Object viewHost = null;
+  Object viewOwner = null;
   String label = null;
 
   _ViewManagerRegisterViewParams() : super(kVersions.last.size);
@@ -70,6 +71,10 @@
     }
     if (mainDataHeader.version >= 0) {
       
+      result.viewOwner = decoder0.decodeInterfaceRequest(20, false, views_mojom.ViewOwnerStub.newFromEndpoint);
+    }
+    if (mainDataHeader.version >= 0) {
+      
       result.label = decoder0.decodeString(24, true);
     }
     return result;
@@ -92,6 +97,13 @@
       rethrow;
     }
     try {
+      encoder0.encodeInterfaceRequest(viewOwner, 20, false);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "viewOwner of struct _ViewManagerRegisterViewParams: $e";
+      rethrow;
+    }
+    try {
       encoder0.encodeString(label, 24, true);
     } on bindings.MojoCodecError catch(e) {
       e.message = "Error encountered while encoding field "
@@ -104,6 +116,7 @@
     return "_ViewManagerRegisterViewParams("
            "view: $view" ", "
            "viewHost: $viewHost" ", "
+           "viewOwner: $viewOwner" ", "
            "label: $label" ")";
   }
 
@@ -116,81 +129,6 @@
 
 
 
-class ViewManagerRegisterViewResponseParams extends bindings.Struct {
-  static const List<bindings.StructDataHeader> kVersions = const [
-    const bindings.StructDataHeader(16, 0)
-  ];
-  views_mojom.ViewToken viewToken = null;
-
-  ViewManagerRegisterViewResponseParams() : super(kVersions.last.size);
-
-  static ViewManagerRegisterViewResponseParams deserialize(bindings.Message message) {
-    var decoder = new bindings.Decoder(message);
-    var result = decode(decoder);
-    if (decoder.excessHandles != null) {
-      decoder.excessHandles.forEach((h) => h.close());
-    }
-    return result;
-  }
-
-  static ViewManagerRegisterViewResponseParams decode(bindings.Decoder decoder0) {
-    if (decoder0 == null) {
-      return null;
-    }
-    ViewManagerRegisterViewResponseParams result = new ViewManagerRegisterViewResponseParams();
-
-    var mainDataHeader = decoder0.decodeStructDataHeader();
-    if (mainDataHeader.version <= kVersions.last.version) {
-      // Scan in reverse order to optimize for more recent versions.
-      for (int i = kVersions.length - 1; i >= 0; --i) {
-        if (mainDataHeader.version >= kVersions[i].version) {
-          if (mainDataHeader.size == kVersions[i].size) {
-            // Found a match.
-            break;
-          }
-          throw new bindings.MojoCodecError(
-              'Header size doesn\'t correspond to known version size.');
-        }
-      }
-    } else if (mainDataHeader.size < kVersions.last.size) {
-      throw new bindings.MojoCodecError(
-        'Message newer than the last known version cannot be shorter than '
-        'required by the last known version.');
-    }
-    if (mainDataHeader.version >= 0) {
-      
-      var decoder1 = decoder0.decodePointer(8, false);
-      result.viewToken = views_mojom.ViewToken.decode(decoder1);
-    }
-    return result;
-  }
-
-  void encode(bindings.Encoder encoder) {
-    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
-    try {
-      encoder0.encodeStruct(viewToken, 8, false);
-    } on bindings.MojoCodecError catch(e) {
-      e.message = "Error encountered while encoding field "
-          "viewToken of struct ViewManagerRegisterViewResponseParams: $e";
-      rethrow;
-    }
-  }
-
-  String toString() {
-    return "ViewManagerRegisterViewResponseParams("
-           "viewToken: $viewToken" ")";
-  }
-
-  Map toJson() {
-    Map map = new Map();
-    map["viewToken"] = viewToken;
-    return map;
-  }
-}
-
-
-
-
 class _ViewManagerRegisterViewTreeParams extends bindings.Struct {
   static const List<bindings.StructDataHeader> kVersions = const [
     const bindings.StructDataHeader(32, 0)
@@ -290,81 +228,6 @@
 
 
 
-class ViewManagerRegisterViewTreeResponseParams extends bindings.Struct {
-  static const List<bindings.StructDataHeader> kVersions = const [
-    const bindings.StructDataHeader(16, 0)
-  ];
-  view_trees_mojom.ViewTreeToken viewTreeToken = null;
-
-  ViewManagerRegisterViewTreeResponseParams() : super(kVersions.last.size);
-
-  static ViewManagerRegisterViewTreeResponseParams deserialize(bindings.Message message) {
-    var decoder = new bindings.Decoder(message);
-    var result = decode(decoder);
-    if (decoder.excessHandles != null) {
-      decoder.excessHandles.forEach((h) => h.close());
-    }
-    return result;
-  }
-
-  static ViewManagerRegisterViewTreeResponseParams decode(bindings.Decoder decoder0) {
-    if (decoder0 == null) {
-      return null;
-    }
-    ViewManagerRegisterViewTreeResponseParams result = new ViewManagerRegisterViewTreeResponseParams();
-
-    var mainDataHeader = decoder0.decodeStructDataHeader();
-    if (mainDataHeader.version <= kVersions.last.version) {
-      // Scan in reverse order to optimize for more recent versions.
-      for (int i = kVersions.length - 1; i >= 0; --i) {
-        if (mainDataHeader.version >= kVersions[i].version) {
-          if (mainDataHeader.size == kVersions[i].size) {
-            // Found a match.
-            break;
-          }
-          throw new bindings.MojoCodecError(
-              'Header size doesn\'t correspond to known version size.');
-        }
-      }
-    } else if (mainDataHeader.size < kVersions.last.size) {
-      throw new bindings.MojoCodecError(
-        'Message newer than the last known version cannot be shorter than '
-        'required by the last known version.');
-    }
-    if (mainDataHeader.version >= 0) {
-      
-      var decoder1 = decoder0.decodePointer(8, false);
-      result.viewTreeToken = view_trees_mojom.ViewTreeToken.decode(decoder1);
-    }
-    return result;
-  }
-
-  void encode(bindings.Encoder encoder) {
-    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
-    try {
-      encoder0.encodeStruct(viewTreeToken, 8, false);
-    } on bindings.MojoCodecError catch(e) {
-      e.message = "Error encountered while encoding field "
-          "viewTreeToken of struct ViewManagerRegisterViewTreeResponseParams: $e";
-      rethrow;
-    }
-  }
-
-  String toString() {
-    return "ViewManagerRegisterViewTreeResponseParams("
-           "viewTreeToken: $viewTreeToken" ")";
-  }
-
-  Map toJson() {
-    Map map = new Map();
-    map["viewTreeToken"] = viewTreeToken;
-    return map;
-  }
-}
-
-
-
-
 const int _ViewManager_registerViewName = 0;
 const int _ViewManager_registerViewTreeName = 1;
 
@@ -380,8 +243,8 @@
 
 abstract class ViewManager {
   static const String serviceName = "mojo::ui::ViewManager";
-  dynamic registerView(Object view,Object viewHost,String label,[Function responseFactory = null]);
-  dynamic registerViewTree(Object viewTree,Object viewTreeHost,String label,[Function responseFactory = null]);
+  void registerView(Object view, Object viewHost, Object viewOwner, String label);
+  void registerViewTree(Object viewTree, Object viewTreeHost, String label);
 }
 
 
@@ -405,46 +268,6 @@
 
   void handleResponse(bindings.ServiceMessage message) {
     switch (message.header.type) {
-      case _ViewManager_registerViewName:
-        var r = ViewManagerRegisterViewResponseParams.deserialize(
-            message.payload);
-        if (!message.header.hasRequestId) {
-          proxyError("Expected a message with a valid request Id.");
-          return;
-        }
-        Completer c = completerMap[message.header.requestId];
-        if (c == null) {
-          proxyError(
-              "Message had unknown request Id: ${message.header.requestId}");
-          return;
-        }
-        completerMap.remove(message.header.requestId);
-        if (c.isCompleted) {
-          proxyError("Response completer already completed");
-          return;
-        }
-        c.complete(r);
-        break;
-      case _ViewManager_registerViewTreeName:
-        var r = ViewManagerRegisterViewTreeResponseParams.deserialize(
-            message.payload);
-        if (!message.header.hasRequestId) {
-          proxyError("Expected a message with a valid request Id.");
-          return;
-        }
-        Completer c = completerMap[message.header.requestId];
-        if (c == null) {
-          proxyError(
-              "Message had unknown request Id: ${message.header.requestId}");
-          return;
-        }
-        completerMap.remove(message.header.requestId);
-        if (c.isCompleted) {
-          proxyError("Response completer already completed");
-          return;
-        }
-        c.complete(r);
-        break;
       default:
         proxyError("Unexpected message type: ${message.header.type}");
         close(immediate: true);
@@ -463,27 +286,28 @@
   _ViewManagerProxyImpl _proxyImpl;
 
   _ViewManagerProxyCalls(this._proxyImpl);
-    dynamic registerView(Object view,Object viewHost,String label,[Function responseFactory = null]) {
+    void registerView(Object view, Object viewHost, Object viewOwner, String label) {
+      if (!_proxyImpl.isBound) {
+        _proxyImpl.proxyError("The Proxy is closed.");
+        return;
+      }
       var params = new _ViewManagerRegisterViewParams();
       params.view = view;
       params.viewHost = viewHost;
+      params.viewOwner = viewOwner;
       params.label = label;
-      return _proxyImpl.sendMessageWithRequestId(
-          params,
-          _ViewManager_registerViewName,
-          -1,
-          bindings.MessageHeader.kMessageExpectsResponse);
+      _proxyImpl.sendMessage(params, _ViewManager_registerViewName);
     }
-    dynamic registerViewTree(Object viewTree,Object viewTreeHost,String label,[Function responseFactory = null]) {
+    void registerViewTree(Object viewTree, Object viewTreeHost, String label) {
+      if (!_proxyImpl.isBound) {
+        _proxyImpl.proxyError("The Proxy is closed.");
+        return;
+      }
       var params = new _ViewManagerRegisterViewTreeParams();
       params.viewTree = viewTree;
       params.viewTreeHost = viewTreeHost;
       params.label = label;
-      return _proxyImpl.sendMessageWithRequestId(
-          params,
-          _ViewManager_registerViewTreeName,
-          -1,
-          bindings.MessageHeader.kMessageExpectsResponse);
+      _proxyImpl.sendMessage(params, _ViewManager_registerViewTreeName);
     }
 }
 
@@ -566,16 +390,6 @@
   }
 
 
-  ViewManagerRegisterViewResponseParams _ViewManagerRegisterViewResponseParamsFactory(views_mojom.ViewToken viewToken) {
-    var mojo_factory_result = new ViewManagerRegisterViewResponseParams();
-    mojo_factory_result.viewToken = viewToken;
-    return mojo_factory_result;
-  }
-  ViewManagerRegisterViewTreeResponseParams _ViewManagerRegisterViewTreeResponseParamsFactory(view_trees_mojom.ViewTreeToken viewTreeToken) {
-    var mojo_factory_result = new ViewManagerRegisterViewTreeResponseParams();
-    mojo_factory_result.viewTreeToken = viewTreeToken;
-    return mojo_factory_result;
-  }
 
   dynamic handleMessage(bindings.ServiceMessage message) {
     if (bindings.ControlMessageHandler.isControlMessage(message)) {
@@ -588,46 +402,12 @@
       case _ViewManager_registerViewName:
         var params = _ViewManagerRegisterViewParams.deserialize(
             message.payload);
-        var response = _impl.registerView(params.view,params.viewHost,params.label,_ViewManagerRegisterViewResponseParamsFactory);
-        if (response is Future) {
-          return response.then((response) {
-            if (response != null) {
-              return buildResponseWithId(
-                  response,
-                  _ViewManager_registerViewName,
-                  message.header.requestId,
-                  bindings.MessageHeader.kMessageIsResponse);
-            }
-          });
-        } else if (response != null) {
-          return buildResponseWithId(
-              response,
-              _ViewManager_registerViewName,
-              message.header.requestId,
-              bindings.MessageHeader.kMessageIsResponse);
-        }
+        _impl.registerView(params.view, params.viewHost, params.viewOwner, params.label);
         break;
       case _ViewManager_registerViewTreeName:
         var params = _ViewManagerRegisterViewTreeParams.deserialize(
             message.payload);
-        var response = _impl.registerViewTree(params.viewTree,params.viewTreeHost,params.label,_ViewManagerRegisterViewTreeResponseParamsFactory);
-        if (response is Future) {
-          return response.then((response) {
-            if (response != null) {
-              return buildResponseWithId(
-                  response,
-                  _ViewManager_registerViewTreeName,
-                  message.header.requestId,
-                  bindings.MessageHeader.kMessageIsResponse);
-            }
-          });
-        } else if (response != null) {
-          return buildResponseWithId(
-              response,
-              _ViewManager_registerViewTreeName,
-              message.header.requestId,
-              bindings.MessageHeader.kMessageIsResponse);
-        }
+        _impl.registerViewTree(params.viewTree, params.viewTreeHost, params.label);
         break;
       default:
         throw new bindings.MojoCodecError("Unexpected message name");
diff --git a/mojo/dart/packages/mojo_services/lib/mojo/ui/view_provider.mojom.dart b/mojo/dart/packages/mojo_services/lib/mojo/ui/view_provider.mojom.dart
index e1e5acf..0052a86 100644
--- a/mojo/dart/packages/mojo_services/lib/mojo/ui/view_provider.mojom.dart
+++ b/mojo/dart/packages/mojo_services/lib/mojo/ui/view_provider.mojom.dart
@@ -19,6 +19,7 @@
   static const List<bindings.StructDataHeader> kVersions = const [
     const bindings.StructDataHeader(24, 0)
   ];
+  Object viewOwner = null;
   Object services = null;
   Object exposedServices = null;
 
@@ -59,11 +60,15 @@
     }
     if (mainDataHeader.version >= 0) {
       
-      result.services = decoder0.decodeInterfaceRequest(8, true, service_provider_mojom.ServiceProviderStub.newFromEndpoint);
+      result.viewOwner = decoder0.decodeInterfaceRequest(8, false, views_mojom.ViewOwnerStub.newFromEndpoint);
     }
     if (mainDataHeader.version >= 0) {
       
-      result.exposedServices = decoder0.decodeServiceInterface(12, true, service_provider_mojom.ServiceProviderProxy.newFromEndpoint);
+      result.services = decoder0.decodeInterfaceRequest(12, true, service_provider_mojom.ServiceProviderStub.newFromEndpoint);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.exposedServices = decoder0.decodeServiceInterface(16, true, service_provider_mojom.ServiceProviderProxy.newFromEndpoint);
     }
     return result;
   }
@@ -71,14 +76,21 @@
   void encode(bindings.Encoder encoder) {
     var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
     try {
-      encoder0.encodeInterfaceRequest(services, 8, true);
+      encoder0.encodeInterfaceRequest(viewOwner, 8, false);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "viewOwner of struct _ViewProviderCreateViewParams: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeInterfaceRequest(services, 12, true);
     } on bindings.MojoCodecError catch(e) {
       e.message = "Error encountered while encoding field "
           "services of struct _ViewProviderCreateViewParams: $e";
       rethrow;
     }
     try {
-      encoder0.encodeInterface(exposedServices, 12, true);
+      encoder0.encodeInterface(exposedServices, 16, true);
     } on bindings.MojoCodecError catch(e) {
       e.message = "Error encountered while encoding field "
           "exposedServices of struct _ViewProviderCreateViewParams: $e";
@@ -88,6 +100,7 @@
 
   String toString() {
     return "_ViewProviderCreateViewParams("
+           "viewOwner: $viewOwner" ", "
            "services: $services" ", "
            "exposedServices: $exposedServices" ")";
   }
@@ -101,81 +114,6 @@
 
 
 
-class ViewProviderCreateViewResponseParams extends bindings.Struct {
-  static const List<bindings.StructDataHeader> kVersions = const [
-    const bindings.StructDataHeader(16, 0)
-  ];
-  views_mojom.ViewToken viewToken = null;
-
-  ViewProviderCreateViewResponseParams() : super(kVersions.last.size);
-
-  static ViewProviderCreateViewResponseParams deserialize(bindings.Message message) {
-    var decoder = new bindings.Decoder(message);
-    var result = decode(decoder);
-    if (decoder.excessHandles != null) {
-      decoder.excessHandles.forEach((h) => h.close());
-    }
-    return result;
-  }
-
-  static ViewProviderCreateViewResponseParams decode(bindings.Decoder decoder0) {
-    if (decoder0 == null) {
-      return null;
-    }
-    ViewProviderCreateViewResponseParams result = new ViewProviderCreateViewResponseParams();
-
-    var mainDataHeader = decoder0.decodeStructDataHeader();
-    if (mainDataHeader.version <= kVersions.last.version) {
-      // Scan in reverse order to optimize for more recent versions.
-      for (int i = kVersions.length - 1; i >= 0; --i) {
-        if (mainDataHeader.version >= kVersions[i].version) {
-          if (mainDataHeader.size == kVersions[i].size) {
-            // Found a match.
-            break;
-          }
-          throw new bindings.MojoCodecError(
-              'Header size doesn\'t correspond to known version size.');
-        }
-      }
-    } else if (mainDataHeader.size < kVersions.last.size) {
-      throw new bindings.MojoCodecError(
-        'Message newer than the last known version cannot be shorter than '
-        'required by the last known version.');
-    }
-    if (mainDataHeader.version >= 0) {
-      
-      var decoder1 = decoder0.decodePointer(8, false);
-      result.viewToken = views_mojom.ViewToken.decode(decoder1);
-    }
-    return result;
-  }
-
-  void encode(bindings.Encoder encoder) {
-    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
-    try {
-      encoder0.encodeStruct(viewToken, 8, false);
-    } on bindings.MojoCodecError catch(e) {
-      e.message = "Error encountered while encoding field "
-          "viewToken of struct ViewProviderCreateViewResponseParams: $e";
-      rethrow;
-    }
-  }
-
-  String toString() {
-    return "ViewProviderCreateViewResponseParams("
-           "viewToken: $viewToken" ")";
-  }
-
-  Map toJson() {
-    Map map = new Map();
-    map["viewToken"] = viewToken;
-    return map;
-  }
-}
-
-
-
-
 const int _ViewProvider_createViewName = 0;
 
 
@@ -190,7 +128,7 @@
 
 abstract class ViewProvider {
   static const String serviceName = "mojo::ui::ViewProvider";
-  dynamic createView(Object services,Object exposedServices,[Function responseFactory = null]);
+  void createView(Object viewOwner, Object services, Object exposedServices);
 }
 
 
@@ -214,26 +152,6 @@
 
   void handleResponse(bindings.ServiceMessage message) {
     switch (message.header.type) {
-      case _ViewProvider_createViewName:
-        var r = ViewProviderCreateViewResponseParams.deserialize(
-            message.payload);
-        if (!message.header.hasRequestId) {
-          proxyError("Expected a message with a valid request Id.");
-          return;
-        }
-        Completer c = completerMap[message.header.requestId];
-        if (c == null) {
-          proxyError(
-              "Message had unknown request Id: ${message.header.requestId}");
-          return;
-        }
-        completerMap.remove(message.header.requestId);
-        if (c.isCompleted) {
-          proxyError("Response completer already completed");
-          return;
-        }
-        c.complete(r);
-        break;
       default:
         proxyError("Unexpected message type: ${message.header.type}");
         close(immediate: true);
@@ -252,15 +170,16 @@
   _ViewProviderProxyImpl _proxyImpl;
 
   _ViewProviderProxyCalls(this._proxyImpl);
-    dynamic createView(Object services,Object exposedServices,[Function responseFactory = null]) {
+    void createView(Object viewOwner, Object services, Object exposedServices) {
+      if (!_proxyImpl.isBound) {
+        _proxyImpl.proxyError("The Proxy is closed.");
+        return;
+      }
       var params = new _ViewProviderCreateViewParams();
+      params.viewOwner = viewOwner;
       params.services = services;
       params.exposedServices = exposedServices;
-      return _proxyImpl.sendMessageWithRequestId(
-          params,
-          _ViewProvider_createViewName,
-          -1,
-          bindings.MessageHeader.kMessageExpectsResponse);
+      _proxyImpl.sendMessage(params, _ViewProvider_createViewName);
     }
 }
 
@@ -343,11 +262,6 @@
   }
 
 
-  ViewProviderCreateViewResponseParams _ViewProviderCreateViewResponseParamsFactory(views_mojom.ViewToken viewToken) {
-    var mojo_factory_result = new ViewProviderCreateViewResponseParams();
-    mojo_factory_result.viewToken = viewToken;
-    return mojo_factory_result;
-  }
 
   dynamic handleMessage(bindings.ServiceMessage message) {
     if (bindings.ControlMessageHandler.isControlMessage(message)) {
@@ -360,24 +274,7 @@
       case _ViewProvider_createViewName:
         var params = _ViewProviderCreateViewParams.deserialize(
             message.payload);
-        var response = _impl.createView(params.services,params.exposedServices,_ViewProviderCreateViewResponseParamsFactory);
-        if (response is Future) {
-          return response.then((response) {
-            if (response != null) {
-              return buildResponseWithId(
-                  response,
-                  _ViewProvider_createViewName,
-                  message.header.requestId,
-                  bindings.MessageHeader.kMessageIsResponse);
-            }
-          });
-        } else if (response != null) {
-          return buildResponseWithId(
-              response,
-              _ViewProvider_createViewName,
-              message.header.requestId,
-              bindings.MessageHeader.kMessageIsResponse);
-        }
+        _impl.createView(params.viewOwner, params.services, params.exposedServices);
         break;
       default:
         throw new bindings.MojoCodecError("Unexpected message name");
diff --git a/mojo/dart/packages/mojo_services/lib/mojo/ui/view_trees.mojom.dart b/mojo/dart/packages/mojo_services/lib/mojo/ui/view_trees.mojom.dart
index a0fa2d0..9cc565e 100644
--- a/mojo/dart/packages/mojo_services/lib/mojo/ui/view_trees.mojom.dart
+++ b/mojo/dart/packages/mojo_services/lib/mojo/ui/view_trees.mojom.dart
@@ -344,6 +344,141 @@
 
 
 
+class _ViewTreeHostGetTokenParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(8, 0)
+  ];
+
+  _ViewTreeHostGetTokenParams() : super(kVersions.last.size);
+
+  static _ViewTreeHostGetTokenParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static _ViewTreeHostGetTokenParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    _ViewTreeHostGetTokenParams result = new _ViewTreeHostGetTokenParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    encoder.getStructEncoderAtOffset(kVersions.last);
+  }
+
+  String toString() {
+    return "_ViewTreeHostGetTokenParams("")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    return map;
+  }
+}
+
+
+
+
+class ViewTreeHostGetTokenResponseParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(16, 0)
+  ];
+  ViewTreeToken token = null;
+
+  ViewTreeHostGetTokenResponseParams() : super(kVersions.last.size);
+
+  static ViewTreeHostGetTokenResponseParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static ViewTreeHostGetTokenResponseParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    ViewTreeHostGetTokenResponseParams result = new ViewTreeHostGetTokenResponseParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      var decoder1 = decoder0.decodePointer(8, false);
+      result.token = ViewTreeToken.decode(decoder1);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeStruct(token, 8, false);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "token of struct ViewTreeHostGetTokenResponseParams: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "ViewTreeHostGetTokenResponseParams("
+           "token: $token" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["token"] = token;
+    return map;
+  }
+}
+
+
+
+
 class _ViewTreeHostGetServiceProviderParams extends bindings.Struct {
   static const List<bindings.StructDataHeader> kVersions = const [
     const bindings.StructDataHeader(16, 0)
@@ -482,7 +617,7 @@
     const bindings.StructDataHeader(24, 0)
   ];
   int rootKey = 0;
-  views_mojom.ViewToken rootViewToken = null;
+  Object rootViewOwner = null;
 
   _ViewTreeHostSetRootParams() : super(kVersions.last.size);
 
@@ -525,8 +660,7 @@
     }
     if (mainDataHeader.version >= 0) {
       
-      var decoder1 = decoder0.decodePointer(16, false);
-      result.rootViewToken = views_mojom.ViewToken.decode(decoder1);
+      result.rootViewOwner = decoder0.decodeServiceInterface(12, false, views_mojom.ViewOwnerProxy.newFromEndpoint);
     }
     return result;
   }
@@ -541,10 +675,10 @@
       rethrow;
     }
     try {
-      encoder0.encodeStruct(rootViewToken, 16, false);
+      encoder0.encodeInterface(rootViewOwner, 12, false);
     } on bindings.MojoCodecError catch(e) {
       e.message = "Error encountered while encoding field "
-          "rootViewToken of struct _ViewTreeHostSetRootParams: $e";
+          "rootViewOwner of struct _ViewTreeHostSetRootParams: $e";
       rethrow;
     }
   }
@@ -552,14 +686,12 @@
   String toString() {
     return "_ViewTreeHostSetRootParams("
            "rootKey: $rootKey" ", "
-           "rootViewToken: $rootViewToken" ")";
+           "rootViewOwner: $rootViewOwner" ")";
   }
 
   Map toJson() {
-    Map map = new Map();
-    map["rootKey"] = rootKey;
-    map["rootViewToken"] = rootViewToken;
-    return map;
+    throw new bindings.MojoCodecError(
+        'Object containing handles cannot be encoded to JSON.');
   }
 }
 
@@ -568,8 +700,9 @@
 
 class _ViewTreeHostResetRootParams extends bindings.Struct {
   static const List<bindings.StructDataHeader> kVersions = const [
-    const bindings.StructDataHeader(8, 0)
+    const bindings.StructDataHeader(16, 0)
   ];
+  Object transferredViewOwner = null;
 
   _ViewTreeHostResetRootParams() : super(kVersions.last.size);
 
@@ -606,20 +739,32 @@
         'Message newer than the last known version cannot be shorter than '
         'required by the last known version.');
     }
+    if (mainDataHeader.version >= 0) {
+      
+      result.transferredViewOwner = decoder0.decodeInterfaceRequest(8, true, views_mojom.ViewOwnerStub.newFromEndpoint);
+    }
     return result;
   }
 
   void encode(bindings.Encoder encoder) {
-    encoder.getStructEncoderAtOffset(kVersions.last);
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeInterfaceRequest(transferredViewOwner, 8, true);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "transferredViewOwner of struct _ViewTreeHostResetRootParams: $e";
+      rethrow;
+    }
   }
 
   String toString() {
-    return "_ViewTreeHostResetRootParams("")";
+    return "_ViewTreeHostResetRootParams("
+           "transferredViewOwner: $transferredViewOwner" ")";
   }
 
   Map toJson() {
-    Map map = new Map();
-    return map;
+    throw new bindings.MojoCodecError(
+        'Object containing handles cannot be encoded to JSON.');
   }
 }
 
@@ -1057,11 +1202,12 @@
     new _ViewTreeServiceDescription();
 }
 
-const int _ViewTreeHost_getServiceProviderName = 0;
-const int _ViewTreeHost_requestLayoutName = 1;
-const int _ViewTreeHost_setRootName = 2;
-const int _ViewTreeHost_resetRootName = 3;
-const int _ViewTreeHost_layoutRootName = 4;
+const int _ViewTreeHost_getTokenName = 0;
+const int _ViewTreeHost_getServiceProviderName = 1;
+const int _ViewTreeHost_requestLayoutName = 2;
+const int _ViewTreeHost_setRootName = 3;
+const int _ViewTreeHost_resetRootName = 4;
+const int _ViewTreeHost_layoutRootName = 5;
 
 
 
@@ -1075,10 +1221,11 @@
 
 abstract class ViewTreeHost {
   static const String serviceName = null;
+  dynamic getToken([Function responseFactory = null]);
   void getServiceProvider(Object serviceProvider);
   void requestLayout();
-  void setRoot(int rootKey, views_mojom.ViewToken rootViewToken);
-  void resetRoot();
+  void setRoot(int rootKey, Object rootViewOwner);
+  void resetRoot(Object transferredViewOwner);
   dynamic layoutRoot(layouts_mojom.ViewLayoutParams rootLayoutParams,[Function responseFactory = null]);
 }
 
@@ -1103,6 +1250,26 @@
 
   void handleResponse(bindings.ServiceMessage message) {
     switch (message.header.type) {
+      case _ViewTreeHost_getTokenName:
+        var r = ViewTreeHostGetTokenResponseParams.deserialize(
+            message.payload);
+        if (!message.header.hasRequestId) {
+          proxyError("Expected a message with a valid request Id.");
+          return;
+        }
+        Completer c = completerMap[message.header.requestId];
+        if (c == null) {
+          proxyError(
+              "Message had unknown request Id: ${message.header.requestId}");
+          return;
+        }
+        completerMap.remove(message.header.requestId);
+        if (c.isCompleted) {
+          proxyError("Response completer already completed");
+          return;
+        }
+        c.complete(r);
+        break;
       case _ViewTreeHost_layoutRootName:
         var r = ViewTreeHostLayoutRootResponseParams.deserialize(
             message.payload);
@@ -1141,6 +1308,14 @@
   _ViewTreeHostProxyImpl _proxyImpl;
 
   _ViewTreeHostProxyCalls(this._proxyImpl);
+    dynamic getToken([Function responseFactory = null]) {
+      var params = new _ViewTreeHostGetTokenParams();
+      return _proxyImpl.sendMessageWithRequestId(
+          params,
+          _ViewTreeHost_getTokenName,
+          -1,
+          bindings.MessageHeader.kMessageExpectsResponse);
+    }
     void getServiceProvider(Object serviceProvider) {
       if (!_proxyImpl.isBound) {
         _proxyImpl.proxyError("The Proxy is closed.");
@@ -1158,22 +1333,23 @@
       var params = new _ViewTreeHostRequestLayoutParams();
       _proxyImpl.sendMessage(params, _ViewTreeHost_requestLayoutName);
     }
-    void setRoot(int rootKey, views_mojom.ViewToken rootViewToken) {
+    void setRoot(int rootKey, Object rootViewOwner) {
       if (!_proxyImpl.isBound) {
         _proxyImpl.proxyError("The Proxy is closed.");
         return;
       }
       var params = new _ViewTreeHostSetRootParams();
       params.rootKey = rootKey;
-      params.rootViewToken = rootViewToken;
+      params.rootViewOwner = rootViewOwner;
       _proxyImpl.sendMessage(params, _ViewTreeHost_setRootName);
     }
-    void resetRoot() {
+    void resetRoot(Object transferredViewOwner) {
       if (!_proxyImpl.isBound) {
         _proxyImpl.proxyError("The Proxy is closed.");
         return;
       }
       var params = new _ViewTreeHostResetRootParams();
+      params.transferredViewOwner = transferredViewOwner;
       _proxyImpl.sendMessage(params, _ViewTreeHost_resetRootName);
     }
     dynamic layoutRoot(layouts_mojom.ViewLayoutParams rootLayoutParams,[Function responseFactory = null]) {
@@ -1266,6 +1442,11 @@
   }
 
 
+  ViewTreeHostGetTokenResponseParams _ViewTreeHostGetTokenResponseParamsFactory(ViewTreeToken token) {
+    var mojo_factory_result = new ViewTreeHostGetTokenResponseParams();
+    mojo_factory_result.token = token;
+    return mojo_factory_result;
+  }
   ViewTreeHostLayoutRootResponseParams _ViewTreeHostLayoutRootResponseParamsFactory(layouts_mojom.ViewLayoutInfo info) {
     var mojo_factory_result = new ViewTreeHostLayoutRootResponseParams();
     mojo_factory_result.info = info;
@@ -1280,6 +1461,28 @@
     }
     assert(_impl != null);
     switch (message.header.type) {
+      case _ViewTreeHost_getTokenName:
+        var params = _ViewTreeHostGetTokenParams.deserialize(
+            message.payload);
+        var response = _impl.getToken(_ViewTreeHostGetTokenResponseParamsFactory);
+        if (response is Future) {
+          return response.then((response) {
+            if (response != null) {
+              return buildResponseWithId(
+                  response,
+                  _ViewTreeHost_getTokenName,
+                  message.header.requestId,
+                  bindings.MessageHeader.kMessageIsResponse);
+            }
+          });
+        } else if (response != null) {
+          return buildResponseWithId(
+              response,
+              _ViewTreeHost_getTokenName,
+              message.header.requestId,
+              bindings.MessageHeader.kMessageIsResponse);
+        }
+        break;
       case _ViewTreeHost_getServiceProviderName:
         var params = _ViewTreeHostGetServiceProviderParams.deserialize(
             message.payload);
@@ -1293,12 +1496,12 @@
       case _ViewTreeHost_setRootName:
         var params = _ViewTreeHostSetRootParams.deserialize(
             message.payload);
-        _impl.setRoot(params.rootKey, params.rootViewToken);
+        _impl.setRoot(params.rootKey, params.rootViewOwner);
         break;
       case _ViewTreeHost_resetRootName:
         var params = _ViewTreeHostResetRootParams.deserialize(
             message.payload);
-        _impl.resetRoot();
+        _impl.resetRoot(params.transferredViewOwner);
         break;
       case _ViewTreeHost_layoutRootName:
         var params = _ViewTreeHostLayoutRootParams.deserialize(
diff --git a/mojo/dart/packages/mojo_services/lib/mojo/ui/views.mojom.dart b/mojo/dart/packages/mojo_services/lib/mojo/ui/views.mojom.dart
index 39df1e1..d00a29a 100644
--- a/mojo/dart/packages/mojo_services/lib/mojo/ui/views.mojom.dart
+++ b/mojo/dart/packages/mojo_services/lib/mojo/ui/views.mojom.dart
@@ -90,6 +90,141 @@
 
 
 
+class _ViewOwnerGetTokenParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(8, 0)
+  ];
+
+  _ViewOwnerGetTokenParams() : super(kVersions.last.size);
+
+  static _ViewOwnerGetTokenParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static _ViewOwnerGetTokenParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    _ViewOwnerGetTokenParams result = new _ViewOwnerGetTokenParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    encoder.getStructEncoderAtOffset(kVersions.last);
+  }
+
+  String toString() {
+    return "_ViewOwnerGetTokenParams("")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    return map;
+  }
+}
+
+
+
+
+class ViewOwnerGetTokenResponseParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(16, 0)
+  ];
+  ViewToken token = null;
+
+  ViewOwnerGetTokenResponseParams() : super(kVersions.last.size);
+
+  static ViewOwnerGetTokenResponseParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static ViewOwnerGetTokenResponseParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    ViewOwnerGetTokenResponseParams result = new ViewOwnerGetTokenResponseParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      var decoder1 = decoder0.decodePointer(8, false);
+      result.token = ViewToken.decode(decoder1);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeStruct(token, 8, false);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "token of struct ViewOwnerGetTokenResponseParams: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "ViewOwnerGetTokenResponseParams("
+           "token: $token" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["token"] = token;
+    return map;
+  }
+}
+
+
+
+
 class _ViewOnLayoutParams extends bindings.Struct {
   static const List<bindings.StructDataHeader> kVersions = const [
     const bindings.StructDataHeader(24, 0)
@@ -388,6 +523,141 @@
 
 
 
+class _ViewHostGetTokenParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(8, 0)
+  ];
+
+  _ViewHostGetTokenParams() : super(kVersions.last.size);
+
+  static _ViewHostGetTokenParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static _ViewHostGetTokenParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    _ViewHostGetTokenParams result = new _ViewHostGetTokenParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    encoder.getStructEncoderAtOffset(kVersions.last);
+  }
+
+  String toString() {
+    return "_ViewHostGetTokenParams("")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    return map;
+  }
+}
+
+
+
+
+class ViewHostGetTokenResponseParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(16, 0)
+  ];
+  ViewToken token = null;
+
+  ViewHostGetTokenResponseParams() : super(kVersions.last.size);
+
+  static ViewHostGetTokenResponseParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static ViewHostGetTokenResponseParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    ViewHostGetTokenResponseParams result = new ViewHostGetTokenResponseParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      var decoder1 = decoder0.decodePointer(8, false);
+      result.token = ViewToken.decode(decoder1);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeStruct(token, 8, false);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "token of struct ViewHostGetTokenResponseParams: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "ViewHostGetTokenResponseParams("
+           "token: $token" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["token"] = token;
+    return map;
+  }
+}
+
+
+
+
 class _ViewHostGetServiceProviderParams extends bindings.Struct {
   static const List<bindings.StructDataHeader> kVersions = const [
     const bindings.StructDataHeader(16, 0)
@@ -599,7 +869,7 @@
     const bindings.StructDataHeader(24, 0)
   ];
   int childKey = 0;
-  ViewToken childViewToken = null;
+  Object childViewOwner = null;
 
   _ViewHostAddChildParams() : super(kVersions.last.size);
 
@@ -642,8 +912,7 @@
     }
     if (mainDataHeader.version >= 0) {
       
-      var decoder1 = decoder0.decodePointer(16, false);
-      result.childViewToken = ViewToken.decode(decoder1);
+      result.childViewOwner = decoder0.decodeServiceInterface(12, false, ViewOwnerProxy.newFromEndpoint);
     }
     return result;
   }
@@ -658,10 +927,10 @@
       rethrow;
     }
     try {
-      encoder0.encodeStruct(childViewToken, 16, false);
+      encoder0.encodeInterface(childViewOwner, 12, false);
     } on bindings.MojoCodecError catch(e) {
       e.message = "Error encountered while encoding field "
-          "childViewToken of struct _ViewHostAddChildParams: $e";
+          "childViewOwner of struct _ViewHostAddChildParams: $e";
       rethrow;
     }
   }
@@ -669,14 +938,12 @@
   String toString() {
     return "_ViewHostAddChildParams("
            "childKey: $childKey" ", "
-           "childViewToken: $childViewToken" ")";
+           "childViewOwner: $childViewOwner" ")";
   }
 
   Map toJson() {
-    Map map = new Map();
-    map["childKey"] = childKey;
-    map["childViewToken"] = childViewToken;
-    return map;
+    throw new bindings.MojoCodecError(
+        'Object containing handles cannot be encoded to JSON.');
   }
 }
 
@@ -688,6 +955,7 @@
     const bindings.StructDataHeader(16, 0)
   ];
   int childKey = 0;
+  Object transferredViewOwner = null;
 
   _ViewHostRemoveChildParams() : super(kVersions.last.size);
 
@@ -728,6 +996,10 @@
       
       result.childKey = decoder0.decodeUint32(8);
     }
+    if (mainDataHeader.version >= 0) {
+      
+      result.transferredViewOwner = decoder0.decodeInterfaceRequest(12, true, ViewOwnerStub.newFromEndpoint);
+    }
     return result;
   }
 
@@ -740,17 +1012,24 @@
           "childKey of struct _ViewHostRemoveChildParams: $e";
       rethrow;
     }
+    try {
+      encoder0.encodeInterfaceRequest(transferredViewOwner, 12, true);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "transferredViewOwner of struct _ViewHostRemoveChildParams: $e";
+      rethrow;
+    }
   }
 
   String toString() {
     return "_ViewHostRemoveChildParams("
-           "childKey: $childKey" ")";
+           "childKey: $childKey" ", "
+           "transferredViewOwner: $transferredViewOwner" ")";
   }
 
   Map toJson() {
-    Map map = new Map();
-    map["childKey"] = childKey;
-    return map;
+    throw new bindings.MojoCodecError(
+        'Object containing handles cannot be encoded to JSON.');
   }
 }
 
@@ -921,6 +1200,231 @@
 
 
 
+const int _ViewOwner_getTokenName = 0;
+
+
+
+class _ViewOwnerServiceDescription implements service_describer.ServiceDescription {
+  dynamic getTopLevelInterface([Function responseFactory]) => null;
+
+  dynamic getTypeDefinition(String typeKey, [Function responseFactory]) => null;
+
+  dynamic getAllTypeDefinitions([Function responseFactory]) => null;
+}
+
+abstract class ViewOwner {
+  static const String serviceName = null;
+  dynamic getToken([Function responseFactory = null]);
+}
+
+
+class _ViewOwnerProxyImpl extends bindings.Proxy {
+  _ViewOwnerProxyImpl.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) : super.fromEndpoint(endpoint);
+
+  _ViewOwnerProxyImpl.fromHandle(core.MojoHandle handle) :
+      super.fromHandle(handle);
+
+  _ViewOwnerProxyImpl.unbound() : super.unbound();
+
+  static _ViewOwnerProxyImpl newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) {
+    assert(endpoint.setDescription("For _ViewOwnerProxyImpl"));
+    return new _ViewOwnerProxyImpl.fromEndpoint(endpoint);
+  }
+
+  service_describer.ServiceDescription get serviceDescription =>
+    new _ViewOwnerServiceDescription();
+
+  void handleResponse(bindings.ServiceMessage message) {
+    switch (message.header.type) {
+      case _ViewOwner_getTokenName:
+        var r = ViewOwnerGetTokenResponseParams.deserialize(
+            message.payload);
+        if (!message.header.hasRequestId) {
+          proxyError("Expected a message with a valid request Id.");
+          return;
+        }
+        Completer c = completerMap[message.header.requestId];
+        if (c == null) {
+          proxyError(
+              "Message had unknown request Id: ${message.header.requestId}");
+          return;
+        }
+        completerMap.remove(message.header.requestId);
+        if (c.isCompleted) {
+          proxyError("Response completer already completed");
+          return;
+        }
+        c.complete(r);
+        break;
+      default:
+        proxyError("Unexpected message type: ${message.header.type}");
+        close(immediate: true);
+        break;
+    }
+  }
+
+  String toString() {
+    var superString = super.toString();
+    return "_ViewOwnerProxyImpl($superString)";
+  }
+}
+
+
+class _ViewOwnerProxyCalls implements ViewOwner {
+  _ViewOwnerProxyImpl _proxyImpl;
+
+  _ViewOwnerProxyCalls(this._proxyImpl);
+    dynamic getToken([Function responseFactory = null]) {
+      var params = new _ViewOwnerGetTokenParams();
+      return _proxyImpl.sendMessageWithRequestId(
+          params,
+          _ViewOwner_getTokenName,
+          -1,
+          bindings.MessageHeader.kMessageExpectsResponse);
+    }
+}
+
+
+class ViewOwnerProxy implements bindings.ProxyBase {
+  final bindings.Proxy impl;
+  ViewOwner ptr;
+
+  ViewOwnerProxy(_ViewOwnerProxyImpl proxyImpl) :
+      impl = proxyImpl,
+      ptr = new _ViewOwnerProxyCalls(proxyImpl);
+
+  ViewOwnerProxy.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) :
+      impl = new _ViewOwnerProxyImpl.fromEndpoint(endpoint) {
+    ptr = new _ViewOwnerProxyCalls(impl);
+  }
+
+  ViewOwnerProxy.fromHandle(core.MojoHandle handle) :
+      impl = new _ViewOwnerProxyImpl.fromHandle(handle) {
+    ptr = new _ViewOwnerProxyCalls(impl);
+  }
+
+  ViewOwnerProxy.unbound() :
+      impl = new _ViewOwnerProxyImpl.unbound() {
+    ptr = new _ViewOwnerProxyCalls(impl);
+  }
+
+  factory ViewOwnerProxy.connectToService(
+      bindings.ServiceConnector s, String url, [String serviceName]) {
+    ViewOwnerProxy p = new ViewOwnerProxy.unbound();
+    s.connectToService(url, p, serviceName);
+    return p;
+  }
+
+  static ViewOwnerProxy newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) {
+    assert(endpoint.setDescription("For ViewOwnerProxy"));
+    return new ViewOwnerProxy.fromEndpoint(endpoint);
+  }
+
+  String get serviceName => ViewOwner.serviceName;
+
+  Future close({bool immediate: false}) => impl.close(immediate: immediate);
+
+  Future responseOrError(Future f) => impl.responseOrError(f);
+
+  Future get errorFuture => impl.errorFuture;
+
+  int get version => impl.version;
+
+  Future<int> queryVersion() => impl.queryVersion();
+
+  void requireVersion(int requiredVersion) {
+    impl.requireVersion(requiredVersion);
+  }
+
+  String toString() {
+    return "ViewOwnerProxy($impl)";
+  }
+}
+
+
+class ViewOwnerStub extends bindings.Stub {
+  ViewOwner _impl = null;
+
+  ViewOwnerStub.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint, [this._impl])
+      : super.fromEndpoint(endpoint);
+
+  ViewOwnerStub.fromHandle(core.MojoHandle handle, [this._impl])
+      : super.fromHandle(handle);
+
+  ViewOwnerStub.unbound() : super.unbound();
+
+  static ViewOwnerStub newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) {
+    assert(endpoint.setDescription("For ViewOwnerStub"));
+    return new ViewOwnerStub.fromEndpoint(endpoint);
+  }
+
+
+  ViewOwnerGetTokenResponseParams _ViewOwnerGetTokenResponseParamsFactory(ViewToken token) {
+    var mojo_factory_result = new ViewOwnerGetTokenResponseParams();
+    mojo_factory_result.token = token;
+    return mojo_factory_result;
+  }
+
+  dynamic handleMessage(bindings.ServiceMessage message) {
+    if (bindings.ControlMessageHandler.isControlMessage(message)) {
+      return bindings.ControlMessageHandler.handleMessage(this,
+                                                          0,
+                                                          message);
+    }
+    assert(_impl != null);
+    switch (message.header.type) {
+      case _ViewOwner_getTokenName:
+        var params = _ViewOwnerGetTokenParams.deserialize(
+            message.payload);
+        var response = _impl.getToken(_ViewOwnerGetTokenResponseParamsFactory);
+        if (response is Future) {
+          return response.then((response) {
+            if (response != null) {
+              return buildResponseWithId(
+                  response,
+                  _ViewOwner_getTokenName,
+                  message.header.requestId,
+                  bindings.MessageHeader.kMessageIsResponse);
+            }
+          });
+        } else if (response != null) {
+          return buildResponseWithId(
+              response,
+              _ViewOwner_getTokenName,
+              message.header.requestId,
+              bindings.MessageHeader.kMessageIsResponse);
+        }
+        break;
+      default:
+        throw new bindings.MojoCodecError("Unexpected message name");
+        break;
+    }
+    return null;
+  }
+
+  ViewOwner get impl => _impl;
+  set impl(ViewOwner d) {
+    assert(_impl == null);
+    _impl = d;
+  }
+
+  String toString() {
+    var superString = super.toString();
+    return "ViewOwnerStub($superString)";
+  }
+
+  int get version => 0;
+
+  service_describer.ServiceDescription get serviceDescription =>
+    new _ViewOwnerServiceDescription();
+}
+
 const int _View_onLayoutName = 0;
 const int _View_onChildUnavailableName = 1;
 
@@ -1205,12 +1709,13 @@
     new _ViewServiceDescription();
 }
 
-const int _ViewHost_getServiceProviderName = 0;
-const int _ViewHost_createSceneName = 1;
-const int _ViewHost_requestLayoutName = 2;
-const int _ViewHost_addChildName = 3;
-const int _ViewHost_removeChildName = 4;
-const int _ViewHost_layoutChildName = 5;
+const int _ViewHost_getTokenName = 0;
+const int _ViewHost_getServiceProviderName = 1;
+const int _ViewHost_createSceneName = 2;
+const int _ViewHost_requestLayoutName = 3;
+const int _ViewHost_addChildName = 4;
+const int _ViewHost_removeChildName = 5;
+const int _ViewHost_layoutChildName = 6;
 
 
 
@@ -1224,11 +1729,12 @@
 
 abstract class ViewHost {
   static const String serviceName = null;
+  dynamic getToken([Function responseFactory = null]);
   void getServiceProvider(Object serviceProvider);
   void createScene(Object scene);
   void requestLayout();
-  void addChild(int childKey, ViewToken childViewToken);
-  void removeChild(int childKey);
+  void addChild(int childKey, Object childViewOwner);
+  void removeChild(int childKey, Object transferredViewOwner);
   dynamic layoutChild(int childKey,layouts_mojom.ViewLayoutParams childLayoutParams,[Function responseFactory = null]);
 }
 
@@ -1253,6 +1759,26 @@
 
   void handleResponse(bindings.ServiceMessage message) {
     switch (message.header.type) {
+      case _ViewHost_getTokenName:
+        var r = ViewHostGetTokenResponseParams.deserialize(
+            message.payload);
+        if (!message.header.hasRequestId) {
+          proxyError("Expected a message with a valid request Id.");
+          return;
+        }
+        Completer c = completerMap[message.header.requestId];
+        if (c == null) {
+          proxyError(
+              "Message had unknown request Id: ${message.header.requestId}");
+          return;
+        }
+        completerMap.remove(message.header.requestId);
+        if (c.isCompleted) {
+          proxyError("Response completer already completed");
+          return;
+        }
+        c.complete(r);
+        break;
       case _ViewHost_layoutChildName:
         var r = ViewHostLayoutChildResponseParams.deserialize(
             message.payload);
@@ -1291,6 +1817,14 @@
   _ViewHostProxyImpl _proxyImpl;
 
   _ViewHostProxyCalls(this._proxyImpl);
+    dynamic getToken([Function responseFactory = null]) {
+      var params = new _ViewHostGetTokenParams();
+      return _proxyImpl.sendMessageWithRequestId(
+          params,
+          _ViewHost_getTokenName,
+          -1,
+          bindings.MessageHeader.kMessageExpectsResponse);
+    }
     void getServiceProvider(Object serviceProvider) {
       if (!_proxyImpl.isBound) {
         _proxyImpl.proxyError("The Proxy is closed.");
@@ -1317,23 +1851,24 @@
       var params = new _ViewHostRequestLayoutParams();
       _proxyImpl.sendMessage(params, _ViewHost_requestLayoutName);
     }
-    void addChild(int childKey, ViewToken childViewToken) {
+    void addChild(int childKey, Object childViewOwner) {
       if (!_proxyImpl.isBound) {
         _proxyImpl.proxyError("The Proxy is closed.");
         return;
       }
       var params = new _ViewHostAddChildParams();
       params.childKey = childKey;
-      params.childViewToken = childViewToken;
+      params.childViewOwner = childViewOwner;
       _proxyImpl.sendMessage(params, _ViewHost_addChildName);
     }
-    void removeChild(int childKey) {
+    void removeChild(int childKey, Object transferredViewOwner) {
       if (!_proxyImpl.isBound) {
         _proxyImpl.proxyError("The Proxy is closed.");
         return;
       }
       var params = new _ViewHostRemoveChildParams();
       params.childKey = childKey;
+      params.transferredViewOwner = transferredViewOwner;
       _proxyImpl.sendMessage(params, _ViewHost_removeChildName);
     }
     dynamic layoutChild(int childKey,layouts_mojom.ViewLayoutParams childLayoutParams,[Function responseFactory = null]) {
@@ -1427,6 +1962,11 @@
   }
 
 
+  ViewHostGetTokenResponseParams _ViewHostGetTokenResponseParamsFactory(ViewToken token) {
+    var mojo_factory_result = new ViewHostGetTokenResponseParams();
+    mojo_factory_result.token = token;
+    return mojo_factory_result;
+  }
   ViewHostLayoutChildResponseParams _ViewHostLayoutChildResponseParamsFactory(layouts_mojom.ViewLayoutInfo info) {
     var mojo_factory_result = new ViewHostLayoutChildResponseParams();
     mojo_factory_result.info = info;
@@ -1441,6 +1981,28 @@
     }
     assert(_impl != null);
     switch (message.header.type) {
+      case _ViewHost_getTokenName:
+        var params = _ViewHostGetTokenParams.deserialize(
+            message.payload);
+        var response = _impl.getToken(_ViewHostGetTokenResponseParamsFactory);
+        if (response is Future) {
+          return response.then((response) {
+            if (response != null) {
+              return buildResponseWithId(
+                  response,
+                  _ViewHost_getTokenName,
+                  message.header.requestId,
+                  bindings.MessageHeader.kMessageIsResponse);
+            }
+          });
+        } else if (response != null) {
+          return buildResponseWithId(
+              response,
+              _ViewHost_getTokenName,
+              message.header.requestId,
+              bindings.MessageHeader.kMessageIsResponse);
+        }
+        break;
       case _ViewHost_getServiceProviderName:
         var params = _ViewHostGetServiceProviderParams.deserialize(
             message.payload);
@@ -1459,12 +2021,12 @@
       case _ViewHost_addChildName:
         var params = _ViewHostAddChildParams.deserialize(
             message.payload);
-        _impl.addChild(params.childKey, params.childViewToken);
+        _impl.addChild(params.childKey, params.childViewOwner);
         break;
       case _ViewHost_removeChildName:
         var params = _ViewHostRemoveChildParams.deserialize(
             message.payload);
-        _impl.removeChild(params.childKey);
+        _impl.removeChild(params.childKey, params.transferredViewOwner);
         break;
       case _ViewHost_layoutChildName:
         var params = _ViewHostLayoutChildParams.deserialize(
diff --git a/mojo/services/ui/views/interfaces/view_manager.mojom b/mojo/services/ui/views/interfaces/view_manager.mojom
index 66f3861..fd67ebd 100644
--- a/mojo/services/ui/views/interfaces/view_manager.mojom
+++ b/mojo/services/ui/views/interfaces/view_manager.mojom
@@ -28,22 +28,26 @@
   // local environment.  The view host is private to the view and should
   // not be shared with anyone else.
   //
-  // The |view_token| is used as a transferable reference which can
+  // The |view_owner| is used as a transferable reference which can
   // be passed to the view's intended container as part of a request to
   // add the view as a child.  The view manager itself does not describe
-  // how this interaction should take place, only that the token should
+  // how this interaction should take place, only that ownership should
   // eventually be passed back through the container's view host interface
-  // as an argument to AddChild().
+  // as an argument to |ViewHost.AddChild()|.
   //
   // The |label| is an optional name to associate with the view for
   // diagnostic purposes.  The label will be truncated if it is longer
   // than |kLabelMaxLength|.
   //
   // To unregister the view and cause it to be removed from the view tree,
-  // simply close the |view| and/or |view_host| message pipes.
+  // simply close the |view|, |view_host|, or |view_owner| message pipes.
+  //
+  // TODO(jeffbrown): Refactor this so View becomes a ViewListener,
+  // ViewHost becomes View, and there are only two pipes here.
   RegisterView(mojo.ui.View view,
                mojo.ui.ViewHost& view_host,
-               string? label) => (mojo.ui.ViewToken view_token);
+               mojo.ui.ViewOwner& view_owner,
+               string? label);
 
   // Registers a view tree with the view manager.
   //
@@ -62,5 +66,5 @@
   // |view_tree_host| message pipes.
   RegisterViewTree(mojo.ui.ViewTree view_tree,
                    mojo.ui.ViewTreeHost& view_tree_host,
-                   string? label) => (mojo.ui.ViewTreeToken view_tree_token);
+                   string? label);
 };
diff --git a/mojo/services/ui/views/interfaces/view_provider.mojom b/mojo/services/ui/views/interfaces/view_provider.mojom
index a1062de..d719f01 100644
--- a/mojo/services/ui/views/interfaces/view_provider.mojom
+++ b/mojo/services/ui/views/interfaces/view_provider.mojom
@@ -15,17 +15,19 @@
 [ServiceName="mojo::ui::ViewProvider"]
 interface ViewProvider {
   // Creates and registers a view with the view manager and returns its
-  // view token (as provided by |ViewManager.RegisterView()|).
+  // view owner which may subsequently be passed to |ViewHost.AddChild()|
+  // to attach the view to a view hierarchy.
   //
-  // Having received the view token, the caller should attach the view to
-  // a view tree and lay it out.
+  // Implementors of this interface are responsible for creating the view
+  // and forwarding the |view_owner| interface request to
+  // |ViewManager.RegisterView()|.
   //
   // The caller may provide services to the view via the |services|
   // service provider.
   //
   // The caller may receive services from the view via the |exposed_services|
   // service provider.
-  CreateView(mojo.ServiceProvider&? services,
-             mojo.ServiceProvider? exposed_services) =>
-                 (ViewToken view_token);
+  CreateView(ViewOwner& view_owner,
+             mojo.ServiceProvider&? services,
+             mojo.ServiceProvider? exposed_services);
 };
diff --git a/mojo/services/ui/views/interfaces/view_trees.mojom b/mojo/services/ui/views/interfaces/view_trees.mojom
index ff7a426..cb545ab 100644
--- a/mojo/services/ui/views/interfaces/view_trees.mojom
+++ b/mojo/services/ui/views/interfaces/view_trees.mojom
@@ -62,6 +62,9 @@
 // ViewManager.  To unregister the view tree, close its view tree
 // and/or view tree host message pipes.
 interface ViewTreeHost {
+  // Gets the view tree's token.
+  GetToken() => (ViewTreeToken token);
+
   // Gets a service provider to access services which are associated with
   // the view tree such as input, accessibility and editing capabilities.
   // The view tree service provider is private to the view tree and should
@@ -81,23 +84,31 @@
   // is set so that callbacks related to the root can be clearly distinguished
   // across these changes.
   //
-  // If |root_view_token| refers to a view which is already unavailable
+  // If |root_view_owner| refers to a view which is already unavailable
   // then the call proceeds as if it succeeded but an OnChildUnavailable()
   // message will be sent.
   //
-  // If |root_view_token| refers to a view which already has a parent or is
+  // If |root_view_owner| refers to a view which already has a parent or is
   // the root of a view tree then an OnChildUnavailable() or OnRootUnavailable()
   // message will be sent to its old parent or root and the the view will be
   // used as the root of the new view tree as usual.  This special case also
   // applies when the specified view is already the root of this view tree, in
   // which case the behavior is similar to the view having been transferred to
   // some other view tree and then back again.
-  SetRoot(uint32 root_key, mojo.ui.ViewToken root_view_token);
+  //
+  // It is an error to call this function if the root has already been set;
+  // the connection will be closed.
+  SetRoot(uint32 root_key, mojo.ui.ViewOwner root_view_owner);
 
   // Removes the root of the view tree.
   //
-  // Does nothing if the view tree currently does not have a root.
-  ResetRoot();
+  // If |transferred_view_owner| is not null, associates it with the previously
+  // configured view or closes the |transferred_view_owner| message pipe
+  // if there was none.
+  //
+  // It is an error to call this function if the root was not previously set;
+  // the connection will be closed.
+  ResetRoot(mojo.ui.ViewOwner&? transferred_view_owner);
 
   // Sets the layout parameters of the root of the view tree and retrieves
   // its layout information.
diff --git a/mojo/services/ui/views/interfaces/views.mojom b/mojo/services/ui/views/interfaces/views.mojom
index 9dbfd31..39f770a 100644
--- a/mojo/services/ui/views/interfaces/views.mojom
+++ b/mojo/services/ui/views/interfaces/views.mojom
@@ -25,6 +25,17 @@
   uint32 value;
 };
 
+// A view owner provides access to the view's token and keeps the
+// view alive.  When the view owner is closed, the view will be
+// unregistered from the view manager.
+//
+// This interface is only intended to be implemented by the view manager
+// to obtain the desired ownership semantics.
+interface ViewOwner {
+  // Gets the |ViewToken| associated with the view.
+  GetToken() => (ViewToken token);
+};
+
 // A view is a graphical user interface component which is responsible
 // for drawing and supporting user interactions in the area of the screen
 // that it occupies.
@@ -100,6 +111,9 @@
 // Each view obtains its own view host when registered with the ViewManager.
 // To unregister the view, close its view host message pipe.
 interface ViewHost {
+  // Gets the view's token.
+  GetToken() => (ViewToken token);
+
   // Gets a service provider to access services which are associated with
   // the view such as input, accessibility and editing capabilities.
   // The view service provider is private to the view and should not be
@@ -123,11 +137,13 @@
   // new layout due to a change in the view's layout information.
   RequestLayout();
 
-  // Adds the view referenced by |child_view_token| as a child and assigns
+  // Adds the view referenced by |child_view_owner| as a child and assigns
   // it the provided |child_key| to identify it among its children.
   // The parent may remove the child later by passing the same |child_key|
   // to RemoveChild().
   //
+  // This method takes ownership of the view.
+  //
   // It is important for the parent to choose locally unique values for
   // |child_key| to ensure that each child can be distinguished even as
   // more children are added or removed.  We recommend using a simple
@@ -136,12 +152,12 @@
   // If the child becomes unavailable at any time prior to being removed
   // then an OnChildUnavailable() message will be sent.
   //
-  // If |child_view_token| refers to a view which is already unavailable or
+  // If |child_view_owner| refers to a view which is already unavailable or
   // if adding the view would create a cycle in the view tree then the
   // call proceeds as if it succeeded but an OnChildUnavailable() message
   // will be sent.
   //
-  // If |child_view_token| refers to a view which already has a parent or is
+  // If |child_view_owner| refers to a view which already has a parent or is
   // the root of a view tree then an OnChildUnavailable() or OnRootUnavailable()
   // message will be sent to its old parent or root and the the view will be
   // (re-)added to its new parent as usual.  This special case also applies
@@ -155,14 +171,18 @@
   //
   // It is an error to add a view whose |child_key| already appears
   // in the view's list of children; the connection will be closed.
-  AddChild(uint32 child_key, mojo.ui.ViewToken child_view_token);
+  AddChild(uint32 child_key, mojo.ui.ViewOwner child_view_owner);
 
   // Removes the view referenced by |child_key| from the view's
   // list of children.
   //
+  // If |transferred_view_owner| is not null, associates it with the
+  // previously added child to allow it to be transferred elsewhere or
+  // closes the |transferred_view_owner| message pipe if there was none.
+  //
   // It is an error to remove a view whose |child_key| does not appear
   // in the parent's list of children; the connection will be closed.
-  RemoveChild(uint32 child_key);
+  RemoveChild(uint32 child_key, mojo.ui.ViewOwner&? transferred_view_owner);
 
   // Sets the layout parameters of the child view referenced by |child_key|
   // and retrieves its layout information.
diff --git a/mojo/ui/base_view.cc b/mojo/ui/base_view.cc
index b58faf4..7ff0068 100644
--- a/mojo/ui/base_view.cc
+++ b/mojo/ui/base_view.cc
@@ -11,16 +11,16 @@
 
 BaseView::BaseView(
     mojo::ApplicationImpl* app_impl,
-    const std::string& label,
-    const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback)
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+    const std::string& label)
     : app_impl_(app_impl), view_binding_(this) {
   DCHECK(app_impl_);
   app_impl_->ConnectToService("mojo:view_manager_service", &view_manager_);
 
   mojo::ui::ViewPtr view;
   view_binding_.Bind(mojo::GetProxy(&view));
-  view_manager_->RegisterView(view.Pass(), mojo::GetProxy(&view_host_), label,
-                              create_view_callback);
+  view_manager_->RegisterView(view.Pass(), mojo::GetProxy(&view_host_),
+                              view_owner_request.Pass(), label);
   view_host_->CreateScene(mojo::GetProxy(&scene_));
   view_host_->GetServiceProvider(mojo::GetProxy(&view_service_provider_));
 }
diff --git a/mojo/ui/base_view.h b/mojo/ui/base_view.h
index 757dcb9..b2cccef 100644
--- a/mojo/ui/base_view.h
+++ b/mojo/ui/base_view.h
@@ -13,7 +13,6 @@
 #include "mojo/public/interfaces/application/service_provider.mojom.h"
 #include "mojo/services/gfx/composition/interfaces/scenes.mojom.h"
 #include "mojo/services/ui/views/interfaces/view_manager.mojom.h"
-#include "mojo/services/ui/views/interfaces/view_provider.mojom.h"
 #include "mojo/services/ui/views/interfaces/views.mojom.h"
 
 namespace mojo {
@@ -29,10 +28,9 @@
  public:
   // TODO(jeffbrown): Consider switching this over to an ApplicationConnector
   // but having ApplicationImpl is handy for simple examples.
-  BaseView(
-      mojo::ApplicationImpl* app_impl,
-      const std::string& label,
-      const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback);
+  BaseView(mojo::ApplicationImpl* app_impl,
+           mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+           const std::string& label);
 
   ~BaseView() override;
 
diff --git a/mojo/ui/ganesh_view.cc b/mojo/ui/ganesh_view.cc
index 56962e5..395888a 100644
--- a/mojo/ui/ganesh_view.cc
+++ b/mojo/ui/ganesh_view.cc
@@ -13,9 +13,9 @@
 
 GaneshView::GaneshView(
     mojo::ApplicationImpl* app_impl,
-    const std::string& label,
-    const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback)
-    : BaseView(app_impl, label, create_view_callback),
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+    const std::string& label)
+    : BaseView(app_impl, view_owner_request.Pass(), label),
       gl_context_owner_(mojo::ApplicationConnectorPtr::Create(
                             app_impl->CreateApplicationConnector())
                             .get()),
diff --git a/mojo/ui/ganesh_view.h b/mojo/ui/ganesh_view.h
index 7cf29e9..7f28e35 100644
--- a/mojo/ui/ganesh_view.h
+++ b/mojo/ui/ganesh_view.h
@@ -21,10 +21,9 @@
 // content for the scene.
 class GaneshView : public BaseView {
  public:
-  GaneshView(
-      mojo::ApplicationImpl* app_impl,
-      const std::string& label,
-      const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback);
+  GaneshView(mojo::ApplicationImpl* app_impl,
+             mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+             const std::string& label);
 
   ~GaneshView() override;
 
diff --git a/mojo/ui/gl_view.cc b/mojo/ui/gl_view.cc
index d07b8cd..27b8c09 100644
--- a/mojo/ui/gl_view.cc
+++ b/mojo/ui/gl_view.cc
@@ -9,11 +9,10 @@
 namespace mojo {
 namespace ui {
 
-GLView::GLView(
-    mojo::ApplicationImpl* app_impl,
-    const std::string& label,
-    const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback)
-    : BaseView(app_impl, label, create_view_callback),
+GLView::GLView(mojo::ApplicationImpl* app_impl,
+               mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+               const std::string& label)
+    : BaseView(app_impl, view_owner_request.Pass(), label),
       gl_context_owner_(ApplicationConnectorPtr::Create(
                             app_impl->CreateApplicationConnector())
                             .get()),
diff --git a/mojo/ui/gl_view.h b/mojo/ui/gl_view.h
index 1f9796c..655cfd4 100644
--- a/mojo/ui/gl_view.h
+++ b/mojo/ui/gl_view.h
@@ -18,10 +18,9 @@
 // content for the scene.
 class GLView : public BaseView {
  public:
-  GLView(
-      mojo::ApplicationImpl* app_impl,
-      const std::string& label,
-      const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback);
+  GLView(mojo::ApplicationImpl* app_impl,
+         mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+         const std::string& label);
 
   ~GLView() override;
 
diff --git a/mojo/ui/view_provider_app.cc b/mojo/ui/view_provider_app.cc
index 40d5a5b..e7b9dd5 100644
--- a/mojo/ui/view_provider_app.cc
+++ b/mojo/ui/view_provider_app.cc
@@ -21,11 +21,11 @@
  private:
   // |ViewProvider|:
   void CreateView(
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
       mojo::InterfaceRequest<mojo::ServiceProvider> services,
-      mojo::ServiceProviderPtr exposed_services,
-      const mojo::ui::ViewProvider::CreateViewCallback& callback) override {
-    app_->CreateView(this, view_provider_url_, services.Pass(),
-                     exposed_services.Pass(), callback);
+      mojo::ServiceProviderPtr exposed_services) override {
+    app_->CreateView(this, view_provider_url_, view_owner_request.Pass(),
+                     services.Pass(), exposed_services.Pass());
   }
 
   ViewProviderApp* app_;
@@ -65,14 +65,11 @@
 void ViewProviderApp::CreateView(
     DelegatingViewProvider* provider,
     const std::string& view_provider_url,
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
     mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services,
-    const mojo::ui::ViewProvider::CreateViewCallback& callback) {
-  if (!CreateView(view_provider_url, services.Pass(), exposed_services.Pass(),
-                  callback)) {
-    bindings_.RemoveBindings(provider);
-    delete provider;
-  }
+    mojo::ServiceProviderPtr exposed_services) {
+  CreateView(view_provider_url, view_owner_request.Pass(), services.Pass(),
+             exposed_services.Pass());
 }
 
 }  // namespace ui
diff --git a/mojo/ui/view_provider_app.h b/mojo/ui/view_provider_app.h
index 07668c6..f5c4b35 100644
--- a/mojo/ui/view_provider_app.h
+++ b/mojo/ui/view_provider_app.h
@@ -42,12 +42,19 @@
   //
   // The |view_provider_url| is the connection URL of the view provider request.
   //
-  // Returns true if successful, false if the view could not be created.
-  virtual bool CreateView(
+  // The |view_owner_request| should be attached to the newly created view
+  // and closed or left pending if the view could not be created.
+  //
+  // The |services| parameter is used to receive services from the view
+  // on behalf of the caller.
+  //
+  // The |exposed_services| parameters is used to provide services to
+  // the view from the caller.
+  virtual void CreateView(
       const std::string& view_provider_url,
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
       mojo::InterfaceRequest<mojo::ServiceProvider> services,
-      mojo::ServiceProviderPtr exposed_services,
-      const mojo::ui::ViewProvider::CreateViewCallback& callback) = 0;
+      mojo::ServiceProviderPtr exposed_services) = 0;
 
  private:
   class DelegatingViewProvider;
@@ -56,11 +63,12 @@
   void Create(mojo::ApplicationConnection* connection,
               mojo::InterfaceRequest<mojo::ui::ViewProvider> request) override;
 
-  void CreateView(DelegatingViewProvider* provider,
-                  const std::string& view_provider_url,
-                  mojo::InterfaceRequest<mojo::ServiceProvider> services,
-                  mojo::ServiceProviderPtr exposed_services,
-                  const mojo::ui::ViewProvider::CreateViewCallback& callback);
+  void CreateView(
+      DelegatingViewProvider* provider,
+      const std::string& view_provider_url,
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+      mojo::InterfaceRequest<mojo::ServiceProvider> services,
+      mojo::ServiceProviderPtr exposed_services);
 
   mojo::ApplicationImpl* app_impl_ = nullptr;
   mojo::StrongBindingSet<mojo::ui::ViewProvider> bindings_;
diff --git a/services/ui/launcher/launcher_app.cc b/services/ui/launcher/launcher_app.cc
index 55a58be..08572b4 100644
--- a/services/ui/launcher/launcher_app.cc
+++ b/services/ui/launcher/launcher_app.cc
@@ -12,6 +12,7 @@
 #include "mojo/public/c/system/main.h"
 #include "mojo/public/cpp/application/application_connection.h"
 #include "mojo/public/cpp/application/application_impl.h"
+#include "mojo/services/ui/views/interfaces/view_provider.mojom.h"
 #include "services/ui/launcher/launcher_view_tree.h"
 
 namespace launcher {
@@ -97,7 +98,8 @@
       compositor_.get(), view_manager_.get(), context_provider.Pass(),
       metrics.Pass(),
       base::Bind(&LauncherApp::Shutdown, base::Unretained(this))));
-  UpdateClientView();
+  view_tree_->SetRoot(client_view_owner_.Pass());
+
   RequestUpdatedViewportMetrics();
 }
 
@@ -123,28 +125,11 @@
 void LauncherApp::LaunchClient(std::string app_url) {
   DVLOG(1) << "Launching " << app_url;
 
-  app_impl_->ConnectToService(app_url, &client_view_provider_);
-  client_view_provider_.set_connection_error_handler(base::Bind(
-      &LauncherApp::OnClientConnectionError, base::Unretained(this)));
+  mojo::ui::ViewProviderPtr client_view_provider;
+  app_impl_->ConnectToService(app_url, &client_view_provider);
 
-  client_view_provider_->CreateView(
-      nullptr, nullptr,
-      base::Bind(&LauncherApp::OnClientViewCreated, base::Unretained(this)));
-}
-
-void LauncherApp::OnClientConnectionError() {
-  LOG(ERROR) << "Exiting due to client application connection error.";
-  Shutdown();
-}
-
-void LauncherApp::OnClientViewCreated(mojo::ui::ViewTokenPtr view_token) {
-  client_view_token_ = view_token.Pass();
-  UpdateClientView();
-}
-
-void LauncherApp::UpdateClientView() {
-  if (view_tree_)
-    view_tree_->SetRoot(client_view_token_.Clone());
+  client_view_provider->CreateView(mojo::GetProxy(&client_view_owner_), nullptr,
+                                   nullptr);
 }
 
 void LauncherApp::Shutdown() {
diff --git a/services/ui/launcher/launcher_app.h b/services/ui/launcher/launcher_app.h
index 9753961..7240b7e 100644
--- a/services/ui/launcher/launcher_app.h
+++ b/services/ui/launcher/launcher_app.h
@@ -13,7 +13,6 @@
 #include "mojo/services/native_viewport/interfaces/native_viewport.mojom.h"
 #include "mojo/services/native_viewport/interfaces/native_viewport_event_dispatcher.mojom.h"
 #include "mojo/services/ui/views/interfaces/view_manager.mojom.h"
-#include "mojo/services/ui/views/interfaces/view_provider.mojom.h"
 
 namespace launcher {
 
@@ -43,8 +42,6 @@
   void RequestUpdatedViewportMetrics();
 
   void LaunchClient(std::string app_url);
-  void OnClientConnectionError();
-  void OnClientViewCreated(mojo::ui::ViewTokenPtr view_token);
 
   void UpdateClientView();
 
@@ -62,8 +59,7 @@
 
   std::unique_ptr<LauncherViewTree> view_tree_;
 
-  mojo::ui::ViewProviderPtr client_view_provider_;
-  mojo::ui::ViewTokenPtr client_view_token_;
+  mojo::ui::ViewOwnerPtr client_view_owner_;
 
   DISALLOW_COPY_AND_ASSIGN(LauncherApp);
 };
diff --git a/services/ui/launcher/launcher_view_tree.cc b/services/ui/launcher/launcher_view_tree.cc
index 1c2beb6..3763e9b 100644
--- a/services/ui/launcher/launcher_view_tree.cc
+++ b/services/ui/launcher/launcher_view_tree.cc
@@ -48,10 +48,8 @@
   // Register the view tree.
   mojo::ui::ViewTreePtr view_tree;
   view_tree_binding_.Bind(mojo::GetProxy(&view_tree));
-  view_manager_->RegisterViewTree(
-      view_tree.Pass(), mojo::GetProxy(&view_tree_host_), "Launcher",
-      base::Bind(&LauncherViewTree::OnViewTreeRegistered,
-                 base::Unretained(this)));
+  view_manager_->RegisterViewTree(view_tree.Pass(),
+                                  mojo::GetProxy(&view_tree_host_), "Launcher");
   view_tree_host_.set_connection_error_handler(base::Bind(
       &LauncherViewTree::OnViewTreeConnectionError, base::Unretained(this)));
 
@@ -68,12 +66,14 @@
 
 LauncherViewTree::~LauncherViewTree() {}
 
-void LauncherViewTree::SetRoot(mojo::ui::ViewTokenPtr token) {
-  root_ = token.Pass();
-  if (root_)
-    view_tree_host_->SetRoot(++root_key_, root_.Clone());
-  else
-    view_tree_host_->ResetRoot();
+void LauncherViewTree::SetRoot(mojo::ui::ViewOwnerPtr owner) {
+  if (owner) {
+    view_tree_host_->SetRoot(++root_key_, owner.Pass());
+    root_was_set_ = true;
+  } else {
+    view_tree_host_->ResetRoot(nullptr);
+    root_was_set_ = false;
+  }
   root_layout_info_.reset();
 }
 
@@ -118,11 +118,6 @@
   SetRootScene();
 }
 
-void LauncherViewTree::OnViewTreeRegistered(
-    mojo::ui::ViewTreeTokenPtr view_tree_token) {
-  DVLOG(1) << "OnViewTreeRegistered: view_tree_token=" << view_tree_token;
-}
-
 void LauncherViewTree::OnResourceUnavailable(
     uint32_t resource_id,
     const OnResourceUnavailableCallback& callback) {
@@ -145,7 +140,7 @@
 }
 
 void LauncherViewTree::LayoutRoot() {
-  if (!root_)
+  if (!root_was_set_)
     return;
 
   auto params = mojo::ui::ViewLayoutParams::New();
diff --git a/services/ui/launcher/launcher_view_tree.h b/services/ui/launcher/launcher_view_tree.h
index 4c4a303..7118c38 100644
--- a/services/ui/launcher/launcher_view_tree.h
+++ b/services/ui/launcher/launcher_view_tree.h
@@ -26,7 +26,7 @@
 
   ~LauncherViewTree() override;
 
-  void SetRoot(mojo::ui::ViewTokenPtr token);
+  void SetRoot(mojo::ui::ViewOwnerPtr owner);
   void SetViewportMetrics(mojo::ViewportMetricsPtr viewport_metrics);
   void DispatchEvent(mojo::EventPtr event);
 
@@ -47,7 +47,6 @@
   void OnInputDispatcherConnectionError();
 
   void OnSceneRegistered(mojo::gfx::composition::SceneTokenPtr scene_token);
-  void OnViewTreeRegistered(mojo::ui::ViewTreeTokenPtr view_tree_token);
 
   void LayoutRoot();
   void OnLayoutResult(mojo::ui::ViewLayoutInfoPtr info);
@@ -76,8 +75,8 @@
   mojo::ui::ViewTreeHostPtr view_tree_host_;
   mojo::ui::InputDispatcherPtr input_dispatcher_;
 
-  mojo::ui::ViewTokenPtr root_;
   uint32_t root_key_ = 0u;
+  bool root_was_set_ = false;
   mojo::ui::ViewLayoutInfoPtr root_layout_info_;
 
   DISALLOW_COPY_AND_ASSIGN(LauncherViewTree);
diff --git a/services/ui/view_manager/BUILD.gn b/services/ui/view_manager/BUILD.gn
index 0a14325..21d322b 100644
--- a/services/ui/view_manager/BUILD.gn
+++ b/services/ui/view_manager/BUILD.gn
@@ -24,6 +24,8 @@
     "view_registry.h",
     "view_state.cc",
     "view_state.h",
+    "view_stub.cc",
+    "view_stub.h",
     "view_tree_host_impl.cc",
     "view_tree_host_impl.h",
     "view_tree_state.cc",
diff --git a/services/ui/view_manager/view_host_impl.cc b/services/ui/view_manager/view_host_impl.cc
index 976644e..7e32e89 100644
--- a/services/ui/view_manager/view_host_impl.cc
+++ b/services/ui/view_manager/view_host_impl.cc
@@ -5,20 +5,21 @@
 #include "services/ui/view_manager/view_host_impl.h"
 
 #include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "services/ui/view_manager/view_registry.h"
+#include "services/ui/view_manager/view_state.h"
 
 namespace view_manager {
 
-ViewHostImpl::ViewHostImpl(
-    ViewRegistry* registry,
-    ViewState* state,
-    mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request)
-    : registry_(registry),
-      state_(state),
-      binding_(this, view_host_request.Pass()) {}
+ViewHostImpl::ViewHostImpl(ViewRegistry* registry, ViewState* state)
+    : registry_(registry), state_(state) {}
 
 ViewHostImpl::~ViewHostImpl() {}
 
+void ViewHostImpl::GetToken(
+    const mojo::ui::ViewHost::GetTokenCallback& callback) {
+  callback.Run(state_->view_token()->Clone());
+}
+
 void ViewHostImpl::GetServiceProvider(
     mojo::InterfaceRequest<mojo::ServiceProvider> service_provider_request) {
   service_provider_bindings_.AddBinding(this, service_provider_request.Pass());
@@ -34,12 +35,15 @@
 }
 
 void ViewHostImpl::AddChild(uint32_t child_key,
-                            mojo::ui::ViewTokenPtr child_view_token) {
-  registry_->AddChild(state_, child_key, child_view_token.Pass());
+                            mojo::ui::ViewOwnerPtr child_view_owner) {
+  registry_->AddChild(state_, child_key, child_view_owner.Pass());
 }
 
-void ViewHostImpl::RemoveChild(uint32_t child_key) {
-  registry_->RemoveChild(state_, child_key);
+void ViewHostImpl::RemoveChild(uint32_t child_key,
+                               mojo::InterfaceRequest<mojo::ui::ViewOwner>
+                                   transferred_view_owner_request) {
+  registry_->RemoveChild(state_, child_key,
+                         transferred_view_owner_request.Pass());
 }
 
 static void RunLayoutChildCallback(
diff --git a/services/ui/view_manager/view_host_impl.h b/services/ui/view_manager/view_host_impl.h
index 907c8f1..2ed54f6 100644
--- a/services/ui/view_manager/view_host_impl.h
+++ b/services/ui/view_manager/view_host_impl.h
@@ -7,36 +7,35 @@
 
 #include "base/macros.h"
 #include "mojo/common/binding_set.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/services/ui/views/interfaces/views.mojom.h"
-#include "services/ui/view_manager/view_registry.h"
-#include "services/ui/view_manager/view_state.h"
 
 namespace view_manager {
 
+class ViewRegistry;
+class ViewState;
+
 // ViewHost interface implementation.
 // This object is owned by its associated ViewState.
-class ViewHostImpl : public mojo::ui::ViewHost, public mojo::ServiceProvider {
+class ViewHostImpl : public mojo::ui::ViewHost,
+                     public mojo::ui::ViewOwner,
+                     public mojo::ServiceProvider {
  public:
-  ViewHostImpl(ViewRegistry* registry,
-               ViewState* state,
-               mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request);
+  ViewHostImpl(ViewRegistry* registry, ViewState* state);
   ~ViewHostImpl() override;
 
-  void set_view_host_connection_error_handler(const base::Closure& handler) {
-    binding_.set_connection_error_handler(handler);
-  }
-
  private:
   // |ViewHost|:
+  void GetToken(const mojo::ui::ViewHost::GetTokenCallback& callback) override;
   void GetServiceProvider(mojo::InterfaceRequest<mojo::ServiceProvider>
                               service_provider_request) override;
   void CreateScene(
       mojo::InterfaceRequest<mojo::gfx::composition::Scene> scene) override;
   void RequestLayout() override;
   void AddChild(uint32_t child_key,
-                mojo::ui::ViewTokenPtr child_view_token) override;
-  void RemoveChild(uint32_t child_key) override;
+                mojo::ui::ViewOwnerPtr child_view_owner) override;
+  void RemoveChild(uint32_t child_key,
+                   mojo::InterfaceRequest<mojo::ui::ViewOwner>
+                       transferred_view_owner_request) override;
   void LayoutChild(uint32_t child_key,
                    mojo::ui::ViewLayoutParamsPtr child_layout_params,
                    const LayoutChildCallback& callback) override;
@@ -47,7 +46,6 @@
 
   ViewRegistry* const registry_;
   ViewState* const state_;
-  mojo::Binding<mojo::ui::ViewHost> binding_;
   mojo::BindingSet<mojo::ServiceProvider> service_provider_bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(ViewHostImpl);
diff --git a/services/ui/view_manager/view_manager_impl.cc b/services/ui/view_manager/view_manager_impl.cc
index fa66868..22e9483 100644
--- a/services/ui/view_manager/view_manager_impl.cc
+++ b/services/ui/view_manager/view_manager_impl.cc
@@ -17,21 +17,18 @@
 void ViewManagerImpl::RegisterView(
     mojo::ui::ViewPtr view,
     mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request,
-    const mojo::String& label,
-    const RegisterViewCallback& callback) {
-  mojo::ui::ViewTokenPtr view_token =
-      registry_->RegisterView(view.Pass(), view_host_request.Pass(), label);
-  callback.Run(view_token.Pass());
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+    const mojo::String& label) {
+  registry_->RegisterView(view.Pass(), view_host_request.Pass(),
+                          view_owner_request.Pass(), label);
 }
 
 void ViewManagerImpl::RegisterViewTree(
     mojo::ui::ViewTreePtr view_tree,
     mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request,
-    const mojo::String& label,
-    const RegisterViewTreeCallback& callback) {
-  mojo::ui::ViewTreeTokenPtr view_tree_token = registry_->RegisterViewTree(
-      view_tree.Pass(), view_tree_host_request.Pass(), label);
-  callback.Run(view_tree_token.Pass());
+    const mojo::String& label) {
+  registry_->RegisterViewTree(view_tree.Pass(), view_tree_host_request.Pass(),
+                              label);
 }
 
 }  // namespace view_manager
diff --git a/services/ui/view_manager/view_manager_impl.h b/services/ui/view_manager/view_manager_impl.h
index 89c463f..fcb490e 100644
--- a/services/ui/view_manager/view_manager_impl.h
+++ b/services/ui/view_manager/view_manager_impl.h
@@ -22,13 +22,12 @@
   void RegisterView(
       mojo::ui::ViewPtr view,
       mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request,
-      const mojo::String& label,
-      const RegisterViewCallback& callback) override;
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
+      const mojo::String& label) override;
   void RegisterViewTree(
       mojo::ui::ViewTreePtr view_tree,
       mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request,
-      const mojo::String& label,
-      const RegisterViewTreeCallback& callback) override;
+      const mojo::String& label) override;
 
   ViewRegistry* registry_;
 
diff --git a/services/ui/view_manager/view_registry.cc b/services/ui/view_manager/view_registry.cc
index a92c7f1..c86177a 100644
--- a/services/ui/view_manager/view_registry.cc
+++ b/services/ui/view_manager/view_registry.cc
@@ -14,8 +14,8 @@
 #include "services/ui/view_manager/view_tree_host_impl.h"
 
 namespace view_manager {
-
-static bool AreViewLayoutParamsValid(const mojo::ui::ViewLayoutParams* params) {
+namespace {
+bool AreViewLayoutParamsValid(const mojo::ui::ViewLayoutParams* params) {
   return params && params->constraints && params->constraints->min_width >= 0 &&
          params->constraints->max_width >= params->constraints->min_width &&
          params->constraints->min_height >= 0 &&
@@ -23,6 +23,14 @@
          params->device_pixel_ratio > 0;
 }
 
+bool IsSizeInBounds(mojo::ui::BoxConstraints* constraints, mojo::Size* size) {
+  return size && size->width >= constraints->min_width &&
+         size->width <= constraints->max_width &&
+         size->height >= constraints->min_height &&
+         size->height <= constraints->max_height;
+}
+}  // namespace
+
 ViewRegistry::ViewRegistry(mojo::gfx::composition::CompositorPtr compositor)
     : compositor_(compositor.Pass()) {}
 
@@ -36,11 +44,14 @@
                                      connection_error_callback);
 }
 
-mojo::ui::ViewTokenPtr ViewRegistry::RegisterView(
+void ViewRegistry::RegisterView(
     mojo::ui::ViewPtr view,
     mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request,
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
     const mojo::String& label) {
   DCHECK(view);
+  DCHECK(view_host_request.is_pending());
+  DCHECK(view_owner_request.is_pending());
 
   auto view_token = mojo::ui::ViewToken::New();
   view_token->value = next_view_token_value_++;
@@ -51,26 +62,19 @@
   std::string sanitized_label =
       label.get().substr(0, mojo::ui::kLabelMaxLength);
   ViewState* view_state =
-      new ViewState(view.Pass(), view_token.Pass(), sanitized_label);
-  ViewHostImpl* view_host =
-      new ViewHostImpl(this, view_state, view_host_request.Pass());
-  view_state->set_view_host(view_host);
-  view_state->set_view_connection_error_handler(
-      base::Bind(&ViewRegistry::OnViewConnectionError, base::Unretained(this),
-                 view_state));
-  view_host->set_view_host_connection_error_handler(
-      base::Bind(&ViewRegistry::OnViewConnectionError, base::Unretained(this),
-                 view_state));
+      new ViewState(this, view.Pass(), view_token.Pass(),
+                    view_host_request.Pass(), sanitized_label);
+  view_state->BindOwner(view_owner_request.Pass());
 
   // Add to registry and return token.
   views_by_token_.insert({view_state->view_token()->value, view_state});
   DVLOG(1) << "RegisterView: view=" << view_state;
-  return view_state->view_token()->Clone();
 }
 
-void ViewRegistry::OnViewConnectionError(ViewState* view_state) {
+void ViewRegistry::OnViewDied(ViewState* view_state,
+                              const std::string& reason) {
   DCHECK(IsViewStateRegisteredDebug(view_state));
-  DVLOG(1) << "OnViewConnectionError: view=" << view_state;
+  DVLOG(1) << "OnViewDied: view=" << view_state << ", reason=" << reason;
 
   UnregisterView(view_state);
 }
@@ -80,18 +84,25 @@
   DVLOG(1) << "UnregisterView: view=" << view_state;
 
   // Remove from parent or roots.
+  // This may send a view unavailable message to the view's parent or tree.
   HijackView(view_state);
 
+  // Recursively unregister all children since they will become unowned
+  // at this point taking care to unlink each one before its unregistration.
+  for (auto& child : view_state->UnlinkAllChildren())
+    UnregisterViewStub(std::move(child));
+
   // Remove from registry.
   views_by_token_.erase(view_state->view_token()->value);
   delete view_state;
 }
 
-mojo::ui::ViewTreeTokenPtr ViewRegistry::RegisterViewTree(
+void ViewRegistry::RegisterViewTree(
     mojo::ui::ViewTreePtr view_tree,
     mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request,
     const mojo::String& label) {
   DCHECK(view_tree);
+  DCHECK(view_tree_host_request.is_pending());
 
   auto view_tree_token = mojo::ui::ViewTreeToken::New();
   view_tree_token->value = next_view_tree_token_value_++;
@@ -101,28 +112,20 @@
   // Create the state and bind host to it.
   std::string sanitized_label =
       label.get().substr(0, mojo::ui::kLabelMaxLength);
-  ViewTreeState* tree_state = new ViewTreeState(
-      view_tree.Pass(), view_tree_token.Pass(), sanitized_label);
-  ViewTreeHostImpl* tree_host =
-      new ViewTreeHostImpl(this, tree_state, view_tree_host_request.Pass());
-  tree_state->set_view_tree_host(tree_host);
-  tree_state->set_view_tree_connection_error_handler(
-      base::Bind(&ViewRegistry::OnViewTreeConnectionError,
-                 base::Unretained(this), tree_state));
-  tree_host->set_view_tree_host_connection_error_handler(
-      base::Bind(&ViewRegistry::OnViewTreeConnectionError,
-                 base::Unretained(this), tree_state));
+  ViewTreeState* tree_state =
+      new ViewTreeState(this, view_tree.Pass(), view_tree_token.Pass(),
+                        view_tree_host_request.Pass(), sanitized_label);
 
   // Add to registry.
   view_trees_by_token_.insert(
       {tree_state->view_tree_token()->value, tree_state});
   DVLOG(1) << "RegisterViewTree: tree=" << tree_state;
-  return tree_state->view_tree_token()->Clone();
 }
 
-void ViewRegistry::OnViewTreeConnectionError(ViewTreeState* tree_state) {
+void ViewRegistry::OnViewTreeDied(ViewTreeState* tree_state,
+                                  const std::string& reason) {
   DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
-  DVLOG(1) << "OnViewTreeConnectionError: tree=" << tree_state;
+  DVLOG(1) << "OnViewTreeDied: tree=" << tree_state << ", reason=" << reason;
 
   UnregisterViewTree(tree_state);
 }
@@ -133,7 +136,7 @@
 
   // Unlink the root if needed.
   if (tree_state->root())
-    UnlinkRoot(tree_state);
+    UnregisterViewStub(tree_state->UnlinkRoot());
 
   // Remove from registry.
   view_trees_by_token_.erase(tree_state->view_tree_token()->value);
@@ -144,6 +147,7 @@
     ViewState* view_state,
     mojo::InterfaceRequest<mojo::gfx::composition::Scene> scene) {
   DCHECK(IsViewStateRegisteredDebug(view_state));
+  DCHECK(scene.is_pending());
   DVLOG(1) << "CreateScene: view=" << view_state;
 
   compositor_->CreateScene(
@@ -175,46 +179,40 @@
 
 void ViewRegistry::AddChild(ViewState* parent_state,
                             uint32_t child_key,
-                            mojo::ui::ViewTokenPtr child_view_token) {
+                            mojo::ui::ViewOwnerPtr child_view_owner) {
   DCHECK(IsViewStateRegisteredDebug(parent_state));
-  DCHECK(child_view_token);
-  DVLOG(1) << "AddChild: parent=" << parent_state << ", child_key=" << child_key
-           << ", child=" << child_view_token;
+  DCHECK(child_view_owner);
+  DVLOG(1) << "AddChild: parent=" << parent_state
+           << ", child_key=" << child_key;
 
-  // Check for duplicate children.
+  // Ensure there are no other children with the same key.
   if (parent_state->children().find(child_key) !=
       parent_state->children().end()) {
     LOG(ERROR) << "View attempted to add a child with a duplicate key: "
-               << "parent=" << parent_state << ", child_key=" << child_key
-               << ", child=" << child_view_token;
+               << "parent=" << parent_state << ", child_key=" << child_key;
     UnregisterView(parent_state);
     return;
   }
 
-  // Check whether the desired child view still exists.
-  // Adding a non-existent child still succeeds but the view manager will
-  // immediately report it as being unavailable.
-  ViewState* child_state = FindView(child_view_token->value);
-  if (!child_state) {
-    LinkChildAsUnavailable(parent_state, child_key);
-    return;
-  }
+  // Add a stub, pending resolution of the view owner.
+  parent_state->LinkChild(child_key, std::unique_ptr<ViewStub>(new ViewStub(
+                                         this, child_view_owner.Pass())));
 
-  // Check whether the child needs to be reparented.
-  // The old parent will receive an unavailable event.  For interface symmetry,
-  // we deliberately do this even if the old and new parents are the same.
-  HijackView(child_state);
-
-  // Link the child into its new parent.
-  LinkChild(parent_state, child_key, child_state);
+  // Schedule layout of the parent on behalf of its newly added child.
+  // We don't need to schedule layout of the child until the parent provides
+  // new layout parameters.
+  InvalidateLayoutForChild(parent_state, child_key);
 }
 
-void ViewRegistry::RemoveChild(ViewState* parent_state, uint32_t child_key) {
+void ViewRegistry::RemoveChild(ViewState* parent_state,
+                               uint32_t child_key,
+                               mojo::InterfaceRequest<mojo::ui::ViewOwner>
+                                   transferred_view_owner_request) {
   DCHECK(IsViewStateRegisteredDebug(parent_state));
   DVLOG(1) << "RemoveChild: parent=" << parent_state
            << ", child_key=" << child_key;
 
-  // Check whether the child key exists in the parent.
+  // Ensure the child key exists in the parent.
   auto child_it = parent_state->children().find(child_key);
   if (child_it == parent_state->children().end()) {
     LOG(ERROR) << "View attempted to remove a child with an invalid key: "
@@ -224,7 +222,13 @@
   }
 
   // Unlink the child from its parent.
-  UnlinkChild(parent_state, child_it);
+  TransferOrUnregisterViewStub(parent_state->UnlinkChild(child_key),
+                               transferred_view_owner_request.Pass());
+
+  // Schedule layout for the parent now that it has lost its child.
+  // We don't need to schedule layout for the child itself since it will
+  // retain its old layout parameters until it is reparented.
+  InvalidateLayout(parent_state);
 }
 
 void ViewRegistry::LayoutChild(
@@ -260,7 +264,7 @@
     return;
   }
 
-  SetLayout(child_it->second, child_layout_params.Pass(), callback);
+  SetLayout(child_it->second.get(), child_layout_params.Pass(), callback);
 }
 
 void ViewRegistry::ConnectToViewService(
@@ -282,32 +286,52 @@
 
 void ViewRegistry::SetRoot(ViewTreeState* tree_state,
                            uint32_t root_key,
-                           mojo::ui::ViewTokenPtr root_view_token) {
+                           mojo::ui::ViewOwnerPtr root_view_owner) {
   DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
-  DCHECK(root_view_token);
-  DVLOG(1) << "SetRoot: tree=" << tree_state << ", root_key=" << root_key
-           << ", root=" << root_view_token;
+  DCHECK(root_view_owner);
+  DVLOG(1) << "SetRoot: tree=" << tree_state << ", root_key=" << root_key;
 
-  // Check whether the desired root view still exists.
-  // Using a non-existent root view still succeeds but the view manager will
-  // immediately report it as being unavailable.
-  ViewState* root_state = FindView(root_view_token->value);
-  if (root_state) {
-    HijackView(root_state);
-    LinkRoot(tree_state, root_state, root_key);
-  } else {
-    SendRootUnavailable(tree_state, root_key);
+  // Ensure there isn't already a root.
+  if (tree_state->root()) {
+    LOG(ERROR)
+        << "View tree attempted to set the root while one is already set: tree="
+        << tree_state << ", root_key=" << root_key;
+    UnregisterViewTree(tree_state);
+    return;
   }
-  tree_state->set_explicit_root(true);
+
+  // Set the root to a stub, pending resolution of the view owner.
+  tree_state->LinkRoot(root_key, std::unique_ptr<ViewStub>(new ViewStub(
+                                     this, root_view_owner.Pass())));
+
+  // Schedule layout of the tree on behalf of its newly added root.
+  // We don't need to schedule layout of the root until the tree provides
+  // new layout parameters.
+  InvalidateLayoutForRoot(tree_state);
 }
 
-void ViewRegistry::ResetRoot(ViewTreeState* tree_state) {
+void ViewRegistry::ResetRoot(ViewTreeState* tree_state,
+                             mojo::InterfaceRequest<mojo::ui::ViewOwner>
+                                 transferred_view_owner_request) {
   DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
   DVLOG(1) << "ResetRoot: tree=" << tree_state;
 
-  if (tree_state->root())
-    UnlinkRoot(tree_state);
-  tree_state->set_explicit_root(false);
+  // Ensure there is a root.
+  if (!tree_state->root()) {
+    LOG(ERROR)
+        << "View tree attempted to reset the root but there is none: tree="
+        << tree_state;
+    UnregisterViewTree(tree_state);
+    return;
+  }
+
+  // Unlink the root from its tree.
+  TransferOrUnregisterViewStub(tree_state->UnlinkRoot(),
+                               transferred_view_owner_request.Pass());
+
+  // Note: We don't need to schedule layout for the root since it will retain
+  // its old layout parameters.  And there's no need to tell the tree
+  // either since it won't have any work to do.  So we're done.
 }
 
 void ViewRegistry::LayoutRoot(ViewTreeState* tree_state,
@@ -331,8 +355,8 @@
 
   // Check whether the client called LayoutRoot without first having actually
   // set a root.
-  if (!tree_state->explicit_root()) {
-    LOG(ERROR) << "View tree attempted to layout the rout without having "
+  if (!tree_state->root()) {
+    LOG(ERROR) << "View tree attempted to layout the root without having "
                   "set one first: tree="
                << tree_state << ", root_layout_params=" << root_layout_params;
     UnregisterViewTree(tree_state);
@@ -340,13 +364,6 @@
     return;
   }
 
-  // Check whether the root is unavailable and therefore cannot be laid out.
-  // This is not an error.
-  if (!tree_state->root()) {
-    callback.Run(nullptr);
-    return;
-  }
-
   SetLayout(tree_state->root(), root_layout_params.Pass(), callback);
 }
 
@@ -366,137 +383,159 @@
   return it != views_by_token_.end() ? it->second : nullptr;
 }
 
-void ViewRegistry::LinkChild(ViewState* parent_state,
-                             uint32_t child_key,
-                             ViewState* child_state) {
-  DCHECK(IsViewStateRegisteredDebug(parent_state));
-  DCHECK(parent_state->children().find(child_key) ==
-         parent_state->children().end());
-  DCHECK(IsViewStateRegisteredDebug(child_state));
-
-  DVLOG(2) << "Added child " << child_key << " {" << child_state->label()
-           << "} to parent {" << parent_state->label() << "}";
-
-  parent_state->children().insert({child_key, child_state});
-  child_state->SetParent(parent_state, child_key);
-
-  // Schedule layout of the parent on behalf of its newly added child.
-  // We don't need to schedule layout of the child until the parent provides
-  // new layout parameters.
-  InvalidateLayoutForChild(parent_state, child_key);
-}
-
-void ViewRegistry::LinkChildAsUnavailable(ViewState* parent_state,
-                                          uint32_t child_key) {
-  DCHECK(IsViewStateRegisteredDebug(parent_state));
-  DCHECK(parent_state->children().find(child_key) ==
-         parent_state->children().end());
-
-  DVLOG(2) << "Added unavailable child " << child_key << " to parent {"
-           << parent_state->label() << "}";
-
-  parent_state->children().insert({child_key, nullptr});
-  SendChildUnavailable(parent_state, child_key);
-
-  // Don't schedule layout for the parent just yet.  Wait for it to
-  // remove its child in response to the OnChildUnavailable notification.
-}
-
-void ViewRegistry::MarkChildAsUnavailable(ViewState* parent_state,
-                                          uint32_t child_key) {
-  DCHECK(IsViewStateRegisteredDebug(parent_state));
-  auto child_it = parent_state->children().find(child_key);
-  DCHECK(child_it != parent_state->children().end());
-  DCHECK(child_it->second);
-
-  DVLOG(2) << "Marked unavailable child " << child_key << " {"
-           << child_it->second->label() << "} from parent {"
-           << parent_state->label() << "}";
-
-  ResetStateWhenUnlinking(child_it->second);
-  child_it->second->ResetContainer();
-  child_it->second = nullptr;
-  SendChildUnavailable(parent_state, child_key);
-
-  // Don't schedule layout for the parent just yet.  Wait for it to
-  // remove its child in response to the OnChildUnavailable notification.
-  // We don't need to schedule layout for the child either since it will
-  // retain its old layout parameters.
-}
-
-void ViewRegistry::UnlinkChild(ViewState* parent_state,
-                               ViewState::ChildrenMap::iterator child_it) {
-  DCHECK(IsViewStateRegisteredDebug(parent_state));
-  DCHECK(child_it != parent_state->children().end());
-
-  ViewState* child_state = child_it->second;
-  if (child_state) {
-    DVLOG(2) << "Removed child " << child_state->key() << " {"
-             << child_state->label() << "} from parent {"
-             << parent_state->label() << "}";
-    ResetStateWhenUnlinking(child_it->second);
-    child_state->ResetContainer();
-  } else {
-    DVLOG(2) << "Removed unavailable child " << child_it->first
-             << "} from parent {" << parent_state->label() << "}";
-  }
-  parent_state->children().erase(child_it);
-
-  // Schedule layout for the parent now that it has lost its child.
-  // We don't need to schedule layout for the child itself since it will
-  // retain its old layout parameters.
-  InvalidateLayout(parent_state);
-}
-
 ViewTreeState* ViewRegistry::FindViewTree(uint32_t view_tree_token_value) {
   auto it = view_trees_by_token_.find(view_tree_token_value);
   return it != view_trees_by_token_.end() ? it->second : nullptr;
 }
 
-void ViewRegistry::LinkRoot(ViewTreeState* tree_state,
-                            ViewState* root_state,
-                            uint32_t root_key) {
-  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
-  DCHECK(IsViewStateRegisteredDebug(root_state));
-  DCHECK(!tree_state->root());
-  DCHECK(!root_state->parent());
-
-  DVLOG(2) << "Linked view tree root " << root_key << " {"
-           << root_state->label() << "}";
-
-  tree_state->SetRoot(root_state, root_key);
-
-  // Schedule layout of the tree on behalf of its newly added root.
-  // We don't need to schedule layout of the root until the tree provides
-  // new layout parameters.
-  InvalidateLayoutForRoot(tree_state);
-}
-
-void ViewRegistry::UnlinkRoot(ViewTreeState* tree_state) {
-  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
-  DCHECK(tree_state->root());
-
-  DVLOG(2) << "Unlinked view tree root " << tree_state->root()->key() << " {"
-           << tree_state->root()->label() << "}";
-
-  ResetStateWhenUnlinking(tree_state->root());
-  tree_state->ResetRoot();
-
-  // We don't need to schedule layout for the root since it will retain
-  // its old layout parameters.
-}
-
 void ViewRegistry::HijackView(ViewState* view_state) {
-  if (view_state->parent()) {
-    MarkChildAsUnavailable(view_state->parent(), view_state->key());
-  } else if (view_state->tree()) {
-    ViewTreeState* tree_state = view_state->tree();
-    uint32_t root_key = tree_state->root()->key();
-    UnlinkRoot(tree_state);
-    SendRootUnavailable(tree_state, root_key);
+  DCHECK(IsViewStateRegisteredDebug(view_state));
+
+  ViewStub* view_stub = view_state->view_stub();
+  if (view_stub)
+    ReleaseViewStubAndNotify(view_stub);
+}
+
+void ViewRegistry::OnViewResolved(ViewStub* view_stub,
+                                  mojo::ui::ViewTokenPtr view_token) {
+  DCHECK(view_stub);
+
+  ViewState* view_state = view_token ? FindView(view_token->value) : nullptr;
+  if (view_state)
+    AttachViewStubAndNotify(view_stub, view_state);
+  else
+    ReleaseViewStubAndNotify(view_stub);
+}
+
+void ViewRegistry::AttachViewStubAndNotify(ViewStub* view_stub,
+                                           ViewState* view_state) {
+  DCHECK(view_stub);
+
+  view_state->ReleaseOwner();  // don't need the ViewOwner pipe anymore
+  view_stub->AttachView(view_state);
+
+  if (view_stub->pending_layout_request()) {
+    view_state->pending_layout_requests().push_back(
+        std::move(view_stub->pending_layout_request()));
+    IssueNextViewLayoutRequest(view_state);
   }
 }
 
+void ViewRegistry::ReleaseViewStubAndNotify(ViewStub* view_stub) {
+  DCHECK(view_stub);
+
+  view_stub->ReleaseView();
+
+  if (view_stub->parent())
+    SendChildUnavailable(view_stub->parent(), view_stub->key());
+  else if (view_stub->tree())
+    SendRootUnavailable(view_stub->tree(), view_stub->key());
+
+  // Note: We don't need to schedule layout for the previous owner.
+  // We can simply wait for it to remove its unavailable child or root in
+  // response to the notification at which point layout will occur.
+  // We don't need to schedule layout for the child either since it will
+  // retain its old layout parameters.
+}
+
+void ViewRegistry::TransferOrUnregisterViewStub(
+    std::unique_ptr<ViewStub> view_stub,
+    mojo::InterfaceRequest<mojo::ui::ViewOwner>
+        transferred_view_owner_request) {
+  DCHECK(view_stub);
+
+  if (transferred_view_owner_request.is_pending()) {
+    if (view_stub->state())
+      view_stub->state()->BindOwner(transferred_view_owner_request.Pass());
+    else if (view_stub->is_pending())
+      CHECK(false);  // TODO(jeffbrown): Handle transfer of pending view
+  } else {
+    UnregisterViewStub(std::move(view_stub));
+  }
+}
+
+void ViewRegistry::UnregisterViewStub(std::unique_ptr<ViewStub> view_stub) {
+  DCHECK(view_stub);
+
+  if (view_stub->state())
+    UnregisterView(view_stub->state());
+}
+
+void ViewRegistry::SetLayout(ViewStub* view_stub,
+                             mojo::ui::ViewLayoutParamsPtr layout_params,
+                             const ViewLayoutCallback& callback) {
+  DCHECK(view_stub);
+  DCHECK(AreViewLayoutParamsValid(layout_params.get()));
+
+  // Immediately discard layout requests on unavailable views.
+  if (view_stub->is_unavailable()) {
+    callback.Run(nullptr);
+    return;
+  }
+
+  // For pending views, only remember the most recent distinct layout request.
+  if (view_stub->is_pending()) {
+    if (!view_stub->pending_layout_request() ||
+        !view_stub->pending_layout_request()->layout_params()->Equals(
+            *layout_params)) {
+      view_stub->pending_layout_request().reset(
+          new ViewLayoutRequest(layout_params.Pass()));
+    }
+    view_stub->pending_layout_request()->AddCallback(callback);
+    return;
+  }
+
+  // For actual views, maintain a queue of pending layout requests.
+  ViewState* view_state = view_stub->state();
+  DCHECK(view_state);
+  DCHECK(!view_stub->pending_layout_request());
+
+  // Check whether the currently cached layout parameters are the same
+  // and we already have a result and we have no pending layout requests.
+  if (view_state->pending_layout_requests().empty() &&
+      view_state->layout_params() &&
+      view_state->layout_params()->Equals(*layout_params)) {
+    mojo::ui::ViewLayoutInfoPtr info = view_state->CreateLayoutInfo();
+    if (info) {
+      DVLOG(2) << "Layout cache hit";
+      view_state->set_scene_changed_since_last_report(false);
+      callback.Run(info.Pass());
+      return;
+    }
+  }
+
+  // Check whether the layout parameters are different from the most
+  // recent pending layout request if we have one.
+  if (view_state->pending_layout_requests().empty() ||
+      !view_state->pending_layout_requests().back()->layout_params()->Equals(
+          *layout_params)) {
+    // Enqueue a new request for these parameters.
+    EnqueueLayoutRequest(view_state, layout_params.Pass());
+  }
+
+  // Enlist ourselves into the callbacks for the pending request.
+  view_state->pending_layout_requests().back()->AddCallback(callback);
+  IssueNextViewLayoutRequest(view_state);
+}
+
+void ViewRegistry::EnqueueLayoutRequest(
+    ViewState* view_state,
+    mojo::ui::ViewLayoutParamsPtr layout_params) {
+  DCHECK(view_state);
+  DCHECK(AreViewLayoutParamsValid(layout_params.get()));
+
+  // Drop the previous layout request if it hasn't been issued yet.
+  // This may cause callbacks to be invoked will null information.
+  if (!view_state->pending_layout_requests().empty() &&
+      !view_state->pending_layout_requests().back()->issued())
+    view_state->pending_layout_requests().pop_back();
+
+  // Enqueue the new request.
+  view_state->pending_layout_requests().emplace_back(
+      std::unique_ptr<ViewLayoutRequest>(
+          new ViewLayoutRequest(layout_params.Pass())));
+}
+
 void ViewRegistry::InvalidateLayout(ViewState* view_state) {
   DCHECK(IsViewStateRegisteredDebug(view_state));
 
@@ -531,138 +570,42 @@
   }
 }
 
-void ViewRegistry::SetLayout(ViewState* view_state,
-                             mojo::ui::ViewLayoutParamsPtr layout_params,
-                             const ViewLayoutCallback& callback) {
-  DCHECK(IsViewStateRegisteredDebug(view_state));
-  DCHECK(AreViewLayoutParamsValid(layout_params.get()));
-
-  // Check whether the currently cached layout parameters are the same
-  // and we already have a result and we have no pending layout requests.
-  if (view_state->pending_layout_requests().empty() &&
-      view_state->layout_params() &&
-      view_state->layout_params()->Equals(*layout_params)) {
-    mojo::ui::ViewLayoutInfoPtr info = view_state->CreateLayoutInfo();
-    if (info) {
-      DVLOG(2) << "Layout cache hit";
-      view_state->set_scene_changed_since_last_report(false);
-      callback.Run(info.Pass());
-      return;
-    }
-  }
-
-  // Check whether the layout parameters are different from the most
-  // recent pending layout request if we have one.
-  if (view_state->pending_layout_requests().empty() ||
-      !view_state->pending_layout_requests().back()->layout_params()->Equals(
-          *layout_params)) {
-    // Enqueue a new request for these parameters.
-    EnqueueLayoutRequest(view_state, layout_params.Pass());
-  }
-
-  // Enlist ourselves into the callbacks for the pending request.
-  view_state->pending_layout_requests().back()->AddCallback(callback);
-  IssueNextViewLayoutRequest(view_state);
-}
-
-void ViewRegistry::EnqueueLayoutRequest(
-    ViewState* view_state,
-    mojo::ui::ViewLayoutParamsPtr layout_params) {
-  DCHECK(IsViewStateRegisteredDebug(view_state));
-  DCHECK(AreViewLayoutParamsValid(layout_params.get()));
-
-  // Drop the previous layout request if it hasn't been issued yet.
-  // This may cause callbacks to be invoked will null information.
-  if (!view_state->pending_layout_requests().empty() &&
-      !view_state->pending_layout_requests().back()->issued())
-    view_state->pending_layout_requests().pop_back();
-
-  // Enqueue the new request.
-  view_state->pending_layout_requests().emplace_back(
-      std::unique_ptr<ViewLayoutRequest>(
-          new ViewLayoutRequest(layout_params.Pass())));
-}
-
 void ViewRegistry::IssueNextViewLayoutRequest(ViewState* view_state) {
   DCHECK(IsViewStateRegisteredDebug(view_state));
 
-  if (!view_state->pending_layout_requests().empty() &&
-      !view_state->pending_layout_requests().front()->issued()) {
-    view_state->pending_layout_requests().front()->set_issued(true);
-    SendViewLayoutRequest(view_state);
-  }
+  if (view_state->pending_layout_requests().empty())
+    return;
+
+  ViewLayoutRequest* request =
+      view_state->pending_layout_requests().front().get();
+  if (request->issued())
+    return;
+
+  // TODO: Detect ANRs
+  DVLOG(1) << "IssueNextViewLayoutRequest: view_state=" << view_state;
+  view_state->view()->OnLayout(
+      request->layout_params()->Clone(),
+      mojo::Array<uint32_t>::From(view_state->children_needing_layout()),
+      base::Bind(&ViewRegistry::OnViewLayoutResult, base::Unretained(this),
+                 view_state->GetWeakPtr()));
+  view_state->children_needing_layout().clear();
+  request->set_issued(true);
 }
 
 void ViewRegistry::IssueNextViewTreeLayoutRequest(ViewTreeState* tree_state) {
   DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
 
-  if (tree_state->layout_request_pending() &&
-      !tree_state->layout_request_issued()) {
-    tree_state->set_layout_request_pending(false);
-    tree_state->set_layout_request_issued(true);
-    SendViewTreeLayoutRequest(tree_state);
-  }
-}
-
-void ViewRegistry::ResetStateWhenUnlinking(ViewState* view_state) {
-  // Clean up parent's recorded state for the child.
-  if (view_state->parent()) {
-    view_state->parent()->children_needing_layout().erase(view_state->key());
-  }
-}
-
-void ViewRegistry::SendChildUnavailable(ViewState* parent_state,
-                                        uint32_t child_key) {
-  DCHECK(IsViewStateRegisteredDebug(parent_state));
-
-  // TODO: Detect ANRs
-  DVLOG(1) << "SendChildUnavailable: child_key=" << child_key;
-  parent_state->view()->OnChildUnavailable(child_key,
-                                           base::Bind(&base::DoNothing));
-}
-
-void ViewRegistry::SendRootUnavailable(ViewTreeState* tree_state,
-                                       uint32_t root_key) {
-  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
-
-  // TODO: Detect ANRs
-  DVLOG(1) << "SendRootUnavailable: root_key=" << root_key;
-  tree_state->view_tree()->OnRootUnavailable(root_key,
-                                             base::Bind(&base::DoNothing));
-}
-
-void ViewRegistry::SendViewLayoutRequest(ViewState* view_state) {
-  DCHECK(IsViewStateRegisteredDebug(view_state));
-  DCHECK(!view_state->pending_layout_requests().empty());
-  DCHECK(view_state->pending_layout_requests().front()->issued());
-
-  // TODO: Detect ANRs
-  DVLOG(1) << "SendViewLayoutRequest: view.token=" << view_state->label();
-  view_state->view()->OnLayout(
-      view_state->pending_layout_requests().front()->layout_params()->Clone(),
-      mojo::Array<uint32_t>::From(view_state->children_needing_layout()),
-      base::Bind(&ViewRegistry::OnViewLayoutResult, base::Unretained(this),
-                 view_state->GetWeakPtr()));
-  view_state->children_needing_layout().clear();
-}
-
-void ViewRegistry::SendViewTreeLayoutRequest(ViewTreeState* tree_state) {
-  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
-  DCHECK(tree_state->layout_request_issued());
+  if (!tree_state->layout_request_pending() ||
+      tree_state->layout_request_issued())
+    return;
 
   // TODO: Detect ANRs
   DVLOG(1) << "SendViewTreeLayoutRequest";
   tree_state->view_tree()->OnLayout(
       base::Bind(&ViewRegistry::OnViewTreeLayoutResult, base::Unretained(this),
                  tree_state->GetWeakPtr()));
-}
-
-static bool IsSizeInBounds(mojo::ui::BoxConstraints* constraints,
-                           mojo::Size* size) {
-  return size && size->width >= constraints->min_width &&
-         size->width <= constraints->max_width &&
-         size->height >= constraints->min_height &&
-         size->height <= constraints->max_height;
+  tree_state->set_layout_request_pending(false);
+  tree_state->set_layout_request_issued(true);
 }
 
 void ViewRegistry::OnViewLayoutResult(base::WeakPtr<ViewState> view_state_weak,
@@ -682,14 +625,14 @@
       view_state->pending_layout_requests().begin());
 
   DVLOG(1) << "OnViewLayoutResult: view=" << view_state
-           << ", params=" << request->layout_params() << ", result=" << result;
+           << ", params=" << *request->layout_params() << ", result=" << result;
 
   // Validate the layout info.
   if (!IsSizeInBounds(request->layout_params()->constraints.get(),
                       result->size.get())) {
     LOG(ERROR) << "View returned invalid size in its layout info: "
                << "view=" << view_state
-               << ", params=" << request->layout_params()
+               << ", params=" << *request->layout_params()
                << ", result=" << result;
     UnregisterView(view_state);
     return;
@@ -713,11 +656,12 @@
     request->DispatchLayoutInfo(info.Pass());
   }
 
-  if (recurse) {
-    if (view_state->parent()) {
-      InvalidateLayoutForChild(view_state->parent(), view_state->key());
-    } else if (view_state->tree()) {
-      InvalidateLayoutForRoot(view_state->tree());
+  if (recurse && view_state->view_stub()) {
+    if (view_state->view_stub()->parent()) {
+      InvalidateLayoutForChild(view_state->view_stub()->parent(),
+                               view_state->view_stub()->key());
+    } else if (view_state->view_stub()->tree()) {
+      InvalidateLayoutForRoot(view_state->view_stub()->tree());
     }
   }
 
@@ -737,4 +681,26 @@
   }
 }
 
+void ViewRegistry::SendChildUnavailable(ViewState* parent_state,
+                                        uint32_t child_key) {
+  DCHECK(IsViewStateRegisteredDebug(parent_state));
+
+  // TODO: Detect ANRs
+  DVLOG(1) << "SendChildUnavailable: parent_state=" << parent_state
+           << ", child_key=" << child_key;
+  parent_state->view()->OnChildUnavailable(child_key,
+                                           base::Bind(&base::DoNothing));
+}
+
+void ViewRegistry::SendRootUnavailable(ViewTreeState* tree_state,
+                                       uint32_t root_key) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+
+  // TODO: Detect ANRs
+  DVLOG(1) << "SendRootUnavailable: tree_state=" << tree_state
+           << ", root_key=" << root_key;
+  tree_state->view_tree()->OnRootUnavailable(root_key,
+                                             base::Bind(&base::DoNothing));
+}
+
 }  // namespace view_manager
diff --git a/services/ui/view_manager/view_registry.h b/services/ui/view_manager/view_registry.h
index c056209..3f2b7ba 100644
--- a/services/ui/view_manager/view_registry.h
+++ b/services/ui/view_manager/view_registry.h
@@ -5,6 +5,7 @@
 #ifndef SERVICES_UI_VIEW_MANAGER_VIEW_REGISTRY_H_
 #define SERVICES_UI_VIEW_MANAGER_VIEW_REGISTRY_H_
 
+#include <string>
 #include <unordered_map>
 
 #include "base/macros.h"
@@ -15,6 +16,7 @@
 #include "services/ui/view_manager/view_associate_table.h"
 #include "services/ui/view_manager/view_layout_request.h"
 #include "services/ui/view_manager/view_state.h"
+#include "services/ui/view_manager/view_stub.h"
 #include "services/ui/view_manager/view_tree_state.h"
 
 namespace view_manager {
@@ -40,17 +42,22 @@
   // VIEW MANAGER REQUESTS
 
   // Registers a view and returns its ViewToken.
-  mojo::ui::ViewTokenPtr RegisterView(
+  void RegisterView(
       mojo::ui::ViewPtr view,
       mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request,
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
       const mojo::String& label);
 
   // Registers a view tree.
-  mojo::ui::ViewTreeTokenPtr RegisterViewTree(
+  void RegisterViewTree(
       mojo::ui::ViewTreePtr view_tree,
       mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request,
       const mojo::String& label);
 
+  // VIEW STUB REQUESTS
+
+  void OnViewResolved(ViewStub* view_stub, mojo::ui::ViewTokenPtr view_token);
+
   // VIEW HOST REQUESTS
 
   // Creates a scene for the view, replacing its current scene.
@@ -66,11 +73,14 @@
   // Destroys |parent_state| if an error occurs.
   void AddChild(ViewState* parent_state,
                 uint32_t child_key,
-                mojo::ui::ViewTokenPtr child_view_token);
+                mojo::ui::ViewOwnerPtr child_view_owner);
 
   // Removes a child.
   // Destroys |parent_state| if an error occurs.
-  void RemoveChild(ViewState* parent_state, uint32_t child_key);
+  void RemoveChild(ViewState* parent_state,
+                   uint32_t child_key,
+                   mojo::InterfaceRequest<mojo::ui::ViewOwner>
+                       transferred_view_owner_request);
 
   // Lays out a child and optionally provides its size.
   // Destroys |parent_state| if an error occurs.
@@ -85,6 +95,9 @@
                             const mojo::String& service_name,
                             mojo::ScopedMessagePipeHandle client_handle);
 
+  // Called when one of the view pipes is closed remotely.
+  void OnViewDied(ViewState* view_state, const std::string& reason);
+
   // VIEW TREE HOST REQUESTS
 
   // Requests layout.
@@ -95,11 +108,13 @@
   // Destroys |tree_state| if an error occurs.
   void SetRoot(ViewTreeState* tree_state,
                uint32_t root_key,
-               mojo::ui::ViewTokenPtr root_view_token);
+               mojo::ui::ViewOwnerPtr root_view_owner);
 
   // Resets the root of the view tree.
   // Destroys |tree_state| if an error occurs.
-  void ResetRoot(ViewTreeState* tree_state);
+  void ResetRoot(ViewTreeState* tree_state,
+                 mojo::InterfaceRequest<mojo::ui::ViewOwner>
+                     transferred_view_owner_request);
 
   // Lays out a view tree's root and optionally provides its size.
   // Destroys |tree_state| if an error occurs.
@@ -113,48 +128,45 @@
                                 const mojo::String& service_name,
                                 mojo::ScopedMessagePipeHandle client_handle);
 
+  // Called when one of the view tree pipes is closed remotely.
+  void OnViewTreeDied(ViewTreeState* tree_state, const std::string& reason);
+
  private:
   // LIFETIME
 
-  void OnViewConnectionError(ViewState* view_state);
   void UnregisterView(ViewState* view_state);
-  void OnViewTreeConnectionError(ViewTreeState* tree_state);
   void UnregisterViewTree(ViewTreeState* tree_state);
 
   // TREE MANIPULATION
 
   ViewState* FindView(uint32_t view_token_value);
-  void LinkChild(ViewState* parent_state,
-                 uint32_t child_key,
-                 ViewState* child_state);
-  void LinkChildAsUnavailable(ViewState* parent_state, uint32_t child_key);
-  void MarkChildAsUnavailable(ViewState* parent_state, uint32_t child_key);
-  void UnlinkChild(ViewState* parent_state,
-                   ViewState::ChildrenMap::iterator child_it);
-
   ViewTreeState* FindViewTree(uint32_t view_tree_token_value);
-  void LinkRoot(ViewTreeState* tree_state,
-                ViewState* root_state,
-                uint32_t root_key);
-  void UnlinkRoot(ViewTreeState* tree_state);
+
   void HijackView(ViewState* view_state);
 
-  // Must be called before the view is actually unlinked from the tree.
-  // Caller is still responsible for actually unlinking the view.
-  void ResetStateWhenUnlinking(ViewState* view_state);
+  void AttachViewStubAndNotify(ViewStub* view_stub, ViewState* view_state);
+  void ReleaseViewStubAndNotify(ViewStub* view_stub);
+  void TransferOrUnregisterViewStub(std::unique_ptr<ViewStub> view_stub,
+                                    mojo::InterfaceRequest<mojo::ui::ViewOwner>
+                                        transferred_view_owner_request);
+  void UnregisterViewStub(std::unique_ptr<ViewStub> view_stub);
 
   // LAYOUT
 
-  void InvalidateLayout(ViewState* view_state);
-  void InvalidateLayoutForChild(ViewState* parent_state, uint32_t child_key);
-  void InvalidateLayoutForRoot(ViewTreeState* tree_state);
-  void SetLayout(ViewState* view_state,
+  void SetLayout(ViewStub* view_stub,
                  mojo::ui::ViewLayoutParamsPtr layout_params,
                  const ViewLayoutCallback& callback);
   void EnqueueLayoutRequest(ViewState* view_state,
                             mojo::ui::ViewLayoutParamsPtr layout_params);
+  void InvalidateLayout(ViewState* view_state);
+  void InvalidateLayoutForChild(ViewState* parent_state, uint32_t child_key);
+  void InvalidateLayoutForRoot(ViewTreeState* tree_state);
+
   void IssueNextViewLayoutRequest(ViewState* view_state);
   void IssueNextViewTreeLayoutRequest(ViewTreeState* tree_state);
+  void OnViewLayoutResult(base::WeakPtr<ViewState> view_state_weak,
+                          mojo::ui::ViewLayoutResultPtr result);
+  void OnViewTreeLayoutResult(base::WeakPtr<ViewTreeState> tree_state_weak);
 
   // SCENE MANAGEMENT
 
@@ -165,11 +177,6 @@
 
   void SendChildUnavailable(ViewState* parent_state, uint32_t child_key);
   void SendRootUnavailable(ViewTreeState* tree_state, uint32_t root_key);
-  void SendViewLayoutRequest(ViewState* view_state);
-  void SendViewTreeLayoutRequest(ViewTreeState* tree_state);
-  void OnViewLayoutResult(base::WeakPtr<ViewState> view_state_weak,
-                          mojo::ui::ViewLayoutResultPtr result);
-  void OnViewTreeLayoutResult(base::WeakPtr<ViewTreeState> tree_state_weak);
 
   bool IsViewStateRegisteredDebug(ViewState* view_state) {
     return view_state && FindView(view_state->view_token()->value);
diff --git a/services/ui/view_manager/view_state.cc b/services/ui/view_manager/view_state.cc
index 643f6f5..70125f4 100644
--- a/services/ui/view_manager/view_state.cc
+++ b/services/ui/view_manager/view_state.cc
@@ -4,52 +4,83 @@
 
 #include "services/ui/view_manager/view_state.h"
 
+#include "base/bind.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
-#include "services/ui/view_manager/view_tree_state.h"
+#include "services/ui/view_manager/view_host_impl.h"
+#include "services/ui/view_manager/view_registry.h"
+#include "services/ui/view_manager/view_stub.h"
 
 namespace view_manager {
 
-ViewState::ViewState(mojo::ui::ViewPtr view,
-                     mojo::ui::ViewTokenPtr view_token,
-                     const std::string& label)
+ViewState::ViewState(
+    ViewRegistry* registry,
+    mojo::ui::ViewPtr view,
+    mojo::ui::ViewTokenPtr view_token,
+    mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request,
+    const std::string& label)
     : view_(view.Pass()),
       view_token_(view_token.Pass()),
       label_(label),
+      impl_(new ViewHostImpl(registry, this)),
+      host_binding_(impl_.get(), view_host_request.Pass()),
+      owner_binding_(impl_.get()),
       weak_factory_(this) {
   DCHECK(view_);
   DCHECK(view_token_);
+
+  view_.set_connection_error_handler(
+      base::Bind(&ViewRegistry::OnViewDied, base::Unretained(registry),
+                 base::Unretained(this), "View connection closed"));
+  host_binding_.set_connection_error_handler(
+      base::Bind(&ViewRegistry::OnViewDied, base::Unretained(registry),
+                 base::Unretained(this), "ViewHost connection closed"));
+  owner_binding_.set_connection_error_handler(
+      base::Bind(&ViewRegistry::OnViewDied, base::Unretained(registry),
+                 base::Unretained(this), "ViewOwner connection closed"));
 }
 
 ViewState::~ViewState() {}
 
-void ViewState::SetTree(ViewTreeState* tree, uint32_t key) {
-  DCHECK(tree);
-  DCHECK(!parent_);  // must be the root
-  if (tree_ != tree) {
-    SetTreeUnchecked(tree);
+void ViewState::LinkChild(uint32_t key, std::unique_ptr<ViewStub> child) {
+  DCHECK(children_.find(key) == children_.end());
+  DCHECK(child);
+  DCHECK(!child->is_linked());
+
+  child->SetParent(this, key);
+  children_.emplace(key, std::move(child));
+}
+
+std::unique_ptr<ViewStub> ViewState::UnlinkChild(uint32_t key) {
+  auto child_it = children_.find(key);
+  DCHECK(child_it != children_.end());
+  std::unique_ptr<ViewStub> child(std::move(child_it->second));
+  child->Unlink();
+  children_.erase(child_it);
+  children_needing_layout_.erase(child->key());
+  return child;
+}
+
+std::vector<std::unique_ptr<ViewStub>> ViewState::UnlinkAllChildren() {
+  std::vector<std::unique_ptr<ViewStub>> stubs;
+  for (auto& pair : children_) {
+    pair.second->Unlink();
+    stubs.push_back(std::move(pair.second));
   }
-  key_ = key;
+  children_.clear();
+  children_needing_layout_.clear();
+  return stubs;
 }
 
-void ViewState::SetTreeUnchecked(ViewTreeState* tree) {
-  tree_ = tree;
-  for (const auto& pair : children_) {
-    pair.second->SetTreeUnchecked(tree);
-  }
+void ViewState::BindOwner(
+    mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request) {
+  DCHECK(!owner_binding_.is_bound());
+  owner_binding_.Bind(view_owner_request.Pass());
 }
 
-void ViewState::SetParent(ViewState* parent, uint32_t key) {
-  DCHECK(parent);
-  parent_ = parent;
-  key_ = key;
-  SetTreeUnchecked(parent->tree_);
-}
-
-void ViewState::ResetContainer() {
-  parent_ = nullptr;
-  key_ = 0;
-  SetTreeUnchecked(nullptr);
+void ViewState::ReleaseOwner() {
+  DCHECK(owner_binding_.is_bound());
+  owner_binding_.Close();
 }
 
 mojo::ui::ViewLayoutInfoPtr ViewState::CreateLayoutInfo() {
@@ -62,7 +93,7 @@
   return info;
 }
 
-const std::string& ViewState::FormattedLabel() {
+const std::string& ViewState::FormattedLabel() const {
   if (formatted_label_cache_.empty()) {
     formatted_label_cache_ =
         label_.empty()
diff --git a/services/ui/view_manager/view_state.h b/services/ui/view_manager/view_state.h
index 2919f91..9b733f6 100644
--- a/services/ui/view_manager/view_state.h
+++ b/services/ui/view_manager/view_state.h
@@ -10,25 +10,29 @@
 #include <string>
 #include <unordered_map>
 
-#include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/services/ui/views/cpp/formatting.h"
 #include "mojo/services/ui/views/interfaces/views.mojom.h"
 #include "services/ui/view_manager/view_layout_request.h"
 
 namespace view_manager {
 
-class ViewTreeState;
+class ViewRegistry;
+class ViewHostImpl;
+class ViewStub;
 
 // Describes the state of a particular view.
 // This object is owned by the ViewRegistry that created it.
 class ViewState {
  public:
-  using ChildrenMap = std::unordered_map<uint32_t, ViewState*>;
+  using ChildrenMap = std::unordered_map<uint32_t, std::unique_ptr<ViewStub>>;
 
-  ViewState(mojo::ui::ViewPtr view,
+  ViewState(ViewRegistry* registry,
+            mojo::ui::ViewPtr view,
             mojo::ui::ViewTokenPtr view_token,
+            mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request,
             const std::string& label);
   ~ViewState();
 
@@ -42,39 +46,24 @@
   // Caller does not obtain ownership of the token.
   mojo::ui::ViewToken* view_token() const { return view_token_.get(); }
 
-  // Sets the associated host implementation and takes ownership of it.
-  void set_view_host(mojo::ui::ViewHost* host) { view_host_.reset(host); }
-
-  // Sets the connection error handler for the view.
-  void set_view_connection_error_handler(const base::Closure& handler) {
-    view_.set_connection_error_handler(handler);
-  }
-
-  // Gets the view tree to which this view belongs, or null if none.
-  ViewTreeState* tree() const { return tree_; }
-
-  // Gets the parent view state, or null if none.
-  ViewState* parent() const { return parent_; }
-
-  // Gets the key that this child has in its container, or 0 if none.
-  uint32_t key() const { return key_; }
-
-  // Recursively sets the view tree to which this view and all of its
-  // descendents belongs.  Must not be null.  This method must only be called
-  // on root views.
-  void SetTree(ViewTreeState* tree, uint32_t key);
-
-  // Sets the parent view state pointer, the child's key in its parent,
-  // and set its view tree to that of its parent.  Must not be null.
-  void SetParent(ViewState* parent, uint32_t key);
-
-  // Resets the parent view state and tree pointers to null.
-  void ResetContainer();
+  // Gets or sets the view stub which links this view into the
+  // view hierarchy, or null if the view isn't linked anywhere.
+  ViewStub* view_stub() const { return view_stub_; }
+  void set_view_stub(ViewStub* view_stub) { view_stub_ = view_stub; }
 
   // The map of children, indexed by child key.
-  // Child view state may be null if the child with the given key has
-  // become unavailable but not yet removed.
-  ChildrenMap& children() { return children_; }
+  // The view stub pointers are never null but some view stubs may
+  // have been marked unavailable.
+  const ChildrenMap& children() const { return children_; }
+
+  // Links a child into the view tree.
+  void LinkChild(uint32_t key, std::unique_ptr<ViewStub> child);
+
+  // Unlinks a child of the view tree.
+  std::unique_ptr<ViewStub> UnlinkChild(uint32_t key);
+
+  // Unlinks all children as a single operation.
+  std::vector<std::unique_ptr<ViewStub>> UnlinkAllChildren();
 
   // The set of children needing layout.
   // This set must never contain non-existent or unavailable children.
@@ -123,21 +112,30 @@
   // Returns null if unavailable.
   mojo::ui::ViewLayoutInfoPtr CreateLayoutInfo();
 
-  const std::string& label() { return label_; }
-  const std::string& FormattedLabel();
+  // Binds the |ViewOwner| interface to the view which has the effect of
+  // tying the view's lifetime to that of the owner's pipe.
+  void BindOwner(
+      mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request);
+
+  // Unbinds the view from its owner.
+  void ReleaseOwner();
+
+  const std::string& label() const { return label_; }
+  const std::string& FormattedLabel() const;
 
  private:
-  void SetTreeUnchecked(ViewTreeState* tree);
-
   mojo::ui::ViewPtr view_;
   mojo::ui::ViewTokenPtr view_token_;
-  const std::string label_;
-  std::string formatted_label_cache_;
 
-  std::unique_ptr<mojo::ui::ViewHost> view_host_;
-  ViewTreeState* tree_ = nullptr;
-  ViewState* parent_ = nullptr;
-  uint32_t key_ = 0u;
+  const std::string label_;
+  mutable std::string formatted_label_cache_;
+
+  std::unique_ptr<ViewHostImpl> impl_;
+  mojo::Binding<mojo::ui::ViewHost> host_binding_;
+  mojo::Binding<mojo::ui::ViewOwner> owner_binding_;
+
+  ViewStub* view_stub_ = nullptr;
+
   ChildrenMap children_;
   std::set<uint32_t> children_needing_layout_;
   std::vector<std::unique_ptr<ViewLayoutRequest>> pending_layout_requests_;
diff --git a/services/ui/view_manager/view_stub.cc b/services/ui/view_manager/view_stub.cc
new file mode 100644
index 0000000..8fd5eae
--- /dev/null
+++ b/services/ui/view_manager/view_stub.cc
@@ -0,0 +1,98 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/ui/view_manager/view_stub.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "services/ui/view_manager/view_registry.h"
+#include "services/ui/view_manager/view_state.h"
+#include "services/ui/view_manager/view_tree_state.h"
+
+namespace view_manager {
+
+ViewStub::ViewStub(ViewRegistry* registry, mojo::ui::ViewOwnerPtr owner)
+    : registry_(registry), owner_(owner.Pass()) {
+  DCHECK(registry_);
+  DCHECK(owner_);
+
+  owner_.set_connection_error_handler(
+      base::Bind(&ViewStub::OnViewResolved, base::Unretained(this), nullptr));
+  owner_->GetToken(
+      base::Bind(&ViewStub::OnViewResolved, base::Unretained(this)));
+}
+
+ViewStub::~ViewStub() {
+  // Ensure that everything was properly released before this object was
+  // destroyed.  The |ViewRegistry| is responsible for maintaining the
+  // invariant that all |ViewState| objects are owned so by the time we
+  // get here, the view should have found a new owner or been unregistered.
+  DCHECK(is_unavailable());
+}
+
+void ViewStub::AttachView(ViewState* state) {
+  DCHECK(state);
+  DCHECK(!state->view_stub());
+  DCHECK(is_pending());
+
+  state_ = state;
+  state_->set_view_stub(this);
+}
+
+ViewState* ViewStub::ReleaseView() {
+  if (is_unavailable())
+    return nullptr;
+
+  ViewState* state = state_;
+  if (state) {
+    DCHECK(state->view_stub() == this);
+    state->set_view_stub(nullptr);
+    state_ = nullptr;
+  }
+  unavailable_ = true;
+  return state;
+}
+
+void ViewStub::SetTree(ViewTreeState* tree, uint32_t key) {
+  DCHECK(tree);
+  DCHECK(!tree_ && !parent_);
+
+  key_ = key;
+  SetTreeRecursively(tree);
+}
+
+void ViewStub::SetParent(ViewState* parent, uint32_t key) {
+  DCHECK(parent);
+  DCHECK(!tree_ && !parent_);
+
+  parent_ = parent;
+  key_ = key;
+  if (parent->view_stub())
+    SetTreeRecursively(parent->view_stub()->tree());
+}
+
+void ViewStub::Unlink() {
+  parent_ = nullptr;
+  key_ = 0;
+  SetTreeRecursively(nullptr);
+}
+
+void ViewStub::SetTreeRecursively(ViewTreeState* tree) {
+  if (tree_ == tree)
+    return;
+  tree_ = tree;
+  if (state_) {
+    for (const auto& pair : state_->children()) {
+      pair.second->SetTreeRecursively(tree);
+    }
+  }
+}
+
+void ViewStub::OnViewResolved(mojo::ui::ViewTokenPtr view_token) {
+  DCHECK(owner_);
+  owner_.reset();
+  registry_->OnViewResolved(this, view_token.Pass());
+}
+
+}  // namespace view_manager
diff --git a/services/ui/view_manager/view_stub.h b/services/ui/view_manager/view_stub.h
new file mode 100644
index 0000000..db031bb
--- /dev/null
+++ b/services/ui/view_manager/view_stub.h
@@ -0,0 +1,110 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_UI_VIEW_MANAGER_VIEW_STUB_H_
+#define SERVICES_UI_VIEW_MANAGER_VIEW_STUB_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "mojo/services/ui/views/interfaces/views.mojom.h"
+#include "services/ui/view_manager/view_layout_request.h"
+
+namespace view_manager {
+
+class ViewRegistry;
+class ViewState;
+class ViewTreeState;
+
+// Describes a link in the view hierarchy either from a parent view to one
+// of its children or from the view tree to its root view.
+//
+// When this object is created, it is not yet known whether the linked
+// view actually exists.  We must wait for a response from the view owner
+// to resolve the view's token and associate the stub with its child.
+//
+// Instances of this object are held by a unique pointer owned by the
+// parent view or view tree at the point where the view is being linked.
+// Note that the lifetime of the views themselves is managed by the view
+// registry.
+class ViewStub {
+ public:
+  // Begins the process of resolving a view.
+  // Invokes |ViewRegistry.OnViewResolved| when the token is obtained
+  // from the owner or passes nullptr if an error occurs.
+  ViewStub(ViewRegistry* registry, mojo::ui::ViewOwnerPtr owner);
+  ~ViewStub();
+
+  // Gets the view state referenced by the stub, or null if the view
+  // has not yet been resolved or is unavailable.
+  ViewState* state() const { return state_; }
+
+  // Returns true if the view which was intended to be referenced by the
+  // stub has become unavailable.
+  bool is_unavailable() const { return unavailable_; }
+
+  // Returns true if awaiting resolution of the view.
+  bool is_pending() const { return !state_ && !unavailable_; }
+
+  // Returns true if the view is linked into a tree or parent.
+  bool is_linked() const { return tree_ && parent_; }
+
+  // Gets the view tree to which this view belongs, or null if none.
+  ViewTreeState* tree() const { return tree_; }
+
+  // Gets the parent view state, or null if none.
+  ViewState* parent() const { return parent_; }
+
+  // Gets the key that this child has in its container, or 0 if none.
+  uint32_t key() const { return key_; }
+
+  // A pending layout request, held until such time as the view is attached.
+  std::unique_ptr<ViewLayoutRequest>& pending_layout_request() {
+    return pending_layout_request_;
+  }
+
+  // Binds the stub to the specified actual view, which must not be null.
+  // Must be called at most once to apply the effects of resolving the
+  // view owner.
+  void AttachView(ViewState* state);
+
+  // Marks the stub as unavailable.
+  // Returns the previous view state, or null if none.
+  ViewState* ReleaseView();
+
+  // THESE METHODS SHOULD ONLY BE CALLED BY VIEW STATE OR VIEW TREE STATE
+
+  // Recursively sets the view tree to which this view and all of its
+  // descendents belong.  Must not be null.  This method must only be called
+  // on root views.
+  void SetTree(ViewTreeState* tree, uint32_t key);
+
+  // Sets the parent view state pointer, the child's key in its parent,
+  // and set its view tree to that of its parent.  Must not be null.
+  void SetParent(ViewState* parent, uint32_t key);
+
+  // Resets the parent view state and tree pointers to null.
+  void Unlink();
+
+ private:
+  void SetTreeRecursively(ViewTreeState* tree);
+  void OnViewResolved(mojo::ui::ViewTokenPtr view_token);
+
+  ViewRegistry* registry_;
+  mojo::ui::ViewOwnerPtr owner_;
+  ViewState* state_ = nullptr;
+  bool unavailable_ = false;
+  std::unique_ptr<ViewLayoutRequest> pending_layout_request_;
+
+  ViewTreeState* tree_ = nullptr;
+  ViewState* parent_ = nullptr;
+  uint32_t key_ = 0u;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewStub);
+};
+
+}  // namespace view_manager
+
+#endif  // SERVICES_UI_VIEW_MANAGER_VIEW_STUB_H_
diff --git a/services/ui/view_manager/view_tree_host_impl.cc b/services/ui/view_manager/view_tree_host_impl.cc
index 654b411..bbfc208 100644
--- a/services/ui/view_manager/view_tree_host_impl.cc
+++ b/services/ui/view_manager/view_tree_host_impl.cc
@@ -5,20 +5,20 @@
 #include "services/ui/view_manager/view_tree_host_impl.h"
 
 #include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "services/ui/view_manager/view_registry.h"
+#include "services/ui/view_manager/view_tree_state.h"
 
 namespace view_manager {
 
-ViewTreeHostImpl::ViewTreeHostImpl(
-    ViewRegistry* registry,
-    ViewTreeState* state,
-    mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request)
-    : registry_(registry),
-      state_(state),
-      binding_(this, view_tree_host_request.Pass()) {}
+ViewTreeHostImpl::ViewTreeHostImpl(ViewRegistry* registry, ViewTreeState* state)
+    : registry_(registry), state_(state) {}
 
 ViewTreeHostImpl::~ViewTreeHostImpl() {}
 
+void ViewTreeHostImpl::GetToken(const GetTokenCallback& callback) {
+  callback.Run(state_->view_tree_token()->Clone());
+}
+
 void ViewTreeHostImpl::GetServiceProvider(
     mojo::InterfaceRequest<mojo::ServiceProvider> service_provider) {
   service_provider_bindings_.AddBinding(this, service_provider.Pass());
@@ -29,12 +29,13 @@
 }
 
 void ViewTreeHostImpl::SetRoot(uint32_t root_key,
-                               mojo::ui::ViewTokenPtr root_view_token) {
-  registry_->SetRoot(state_, root_key, root_view_token.Pass());
+                               mojo::ui::ViewOwnerPtr root_view_owner) {
+  registry_->SetRoot(state_, root_key, root_view_owner.Pass());
 }
 
-void ViewTreeHostImpl::ResetRoot() {
-  registry_->ResetRoot(state_);
+void ViewTreeHostImpl::ResetRoot(mojo::InterfaceRequest<mojo::ui::ViewOwner>
+                                     transferred_view_owner_request) {
+  registry_->ResetRoot(state_, transferred_view_owner_request.Pass());
 }
 
 static void RunLayoutRootCallback(
diff --git a/services/ui/view_manager/view_tree_host_impl.h b/services/ui/view_manager/view_tree_host_impl.h
index 017ee88..4c832f1 100644
--- a/services/ui/view_manager/view_tree_host_impl.h
+++ b/services/ui/view_manager/view_tree_host_impl.h
@@ -7,37 +7,31 @@
 
 #include "base/macros.h"
 #include "mojo/common/binding_set.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/services/ui/views/interfaces/view_trees.mojom.h"
-#include "services/ui/view_manager/view_registry.h"
-#include "services/ui/view_manager/view_tree_state.h"
 
 namespace view_manager {
 
+class ViewRegistry;
+class ViewTreeState;
+
 // ViewTreeHost interface implementation.
 // This object is owned by its associated ViewTreeState.
 class ViewTreeHostImpl : public mojo::ui::ViewTreeHost,
                          public mojo::ServiceProvider {
  public:
-  ViewTreeHostImpl(
-      ViewRegistry* registry,
-      ViewTreeState* state,
-      mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request);
+  ViewTreeHostImpl(ViewRegistry* registry, ViewTreeState* state);
   ~ViewTreeHostImpl() override;
 
-  void set_view_tree_host_connection_error_handler(
-      const base::Closure& handler) {
-    binding_.set_connection_error_handler(handler);
-  }
-
  private:
   // |ViewTreeHost|:
+  void GetToken(const GetTokenCallback& callback) override;
   void GetServiceProvider(
       mojo::InterfaceRequest<mojo::ServiceProvider> service_provider) override;
   void RequestLayout() override;
   void SetRoot(uint32_t root_key,
-               mojo::ui::ViewTokenPtr root_view_token) override;
-  void ResetRoot() override;
+               mojo::ui::ViewOwnerPtr root_view_owner) override;
+  void ResetRoot(mojo::InterfaceRequest<mojo::ui::ViewOwner>
+                     transferred_view_owner_request) override;
   void LayoutRoot(mojo::ui::ViewLayoutParamsPtr root_layout_params,
                   const LayoutRootCallback& callback) override;
 
@@ -47,7 +41,6 @@
 
   ViewRegistry* const registry_;
   ViewTreeState* const state_;
-  mojo::Binding<mojo::ui::ViewTreeHost> binding_;
   mojo::BindingSet<mojo::ServiceProvider> service_provider_bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(ViewTreeHostImpl);
diff --git a/services/ui/view_manager/view_tree_state.cc b/services/ui/view_manager/view_tree_state.cc
index 4a69f2c..1d8f502 100644
--- a/services/ui/view_manager/view_tree_state.cc
+++ b/services/ui/view_manager/view_tree_state.cc
@@ -4,41 +4,56 @@
 
 #include "services/ui/view_manager/view_tree_state.h"
 
+#include "base/bind.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
+#include "services/ui/view_manager/view_registry.h"
+#include "services/ui/view_manager/view_state.h"
+#include "services/ui/view_manager/view_stub.h"
+#include "services/ui/view_manager/view_tree_host_impl.h"
 
 namespace view_manager {
 
-ViewTreeState::ViewTreeState(mojo::ui::ViewTreePtr view_tree,
-                             mojo::ui::ViewTreeTokenPtr view_tree_token,
-                             const std::string& label)
+ViewTreeState::ViewTreeState(
+    ViewRegistry* registry,
+    mojo::ui::ViewTreePtr view_tree,
+    mojo::ui::ViewTreeTokenPtr view_tree_token,
+    mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request,
+    const std::string& label)
     : view_tree_(view_tree.Pass()),
       view_tree_token_(view_tree_token.Pass()),
       label_(label),
+      impl_(new ViewTreeHostImpl(registry, this)),
+      host_binding_(impl_.get(), view_tree_host_request.Pass()),
       weak_factory_(this) {
   DCHECK(view_tree_);
   DCHECK(view_tree_token_);
+
+  view_tree_.set_connection_error_handler(
+      base::Bind(&ViewRegistry::OnViewTreeDied, base::Unretained(registry),
+                 base::Unretained(this), "ViewTree connection closed"));
+  host_binding_.set_connection_error_handler(
+      base::Bind(&ViewRegistry::OnViewTreeDied, base::Unretained(registry),
+                 base::Unretained(this), "ViewTreeHost connection closed"));
 }
 
 ViewTreeState::~ViewTreeState() {}
 
-void ViewTreeState::SetRoot(ViewState* root, uint32_t key) {
+void ViewTreeState::LinkRoot(uint32_t key, std::unique_ptr<ViewStub> root) {
+  DCHECK(!root_);
   DCHECK(root);
-  if (root_ != root) {
-    ResetRoot();
-    root->SetTree(this, key);
-    root_ = root;
-  }
+  DCHECK(!root->is_linked());
+  root->SetTree(this, key);
+  root_ = std::move(root);
 }
 
-void ViewTreeState::ResetRoot() {
-  if (root_) {
-    root_->ResetContainer();
-  }
-  root_ = nullptr;
+std::unique_ptr<ViewStub> ViewTreeState::UnlinkRoot() {
+  DCHECK(root_);
+  root_->Unlink();
+  return std::move(root_);
 }
 
-const std::string& ViewTreeState::FormattedLabel() {
+const std::string& ViewTreeState::FormattedLabel() const {
   if (formatted_label_cache_.empty()) {
     formatted_label_cache_ =
         label_.empty() ? base::StringPrintf("<%d>", view_tree_token_->value)
diff --git a/services/ui/view_manager/view_tree_state.h b/services/ui/view_manager/view_tree_state.h
index a6ea845..d1cfc98 100644
--- a/services/ui/view_manager/view_tree_state.h
+++ b/services/ui/view_manager/view_tree_state.h
@@ -10,24 +10,29 @@
 #include <string>
 #include <unordered_map>
 
-#include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "mojo/common/binding_set.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/services/ui/views/cpp/formatting.h"
 #include "mojo/services/ui/views/interfaces/view_trees.mojom.h"
-#include "services/ui/view_manager/view_state.h"
 
 namespace view_manager {
 
+class ViewRegistry;
+class ViewState;
+class ViewStub;
+class ViewTreeHostImpl;
+
 // Describes the state of a particular view tree.
 // This object is owned by the ViewRegistry that created it.
 class ViewTreeState {
  public:
-  explicit ViewTreeState(mojo::ui::ViewTreePtr view_tree,
-                         mojo::ui::ViewTreeTokenPtr view_tree_token,
-                         const std::string& label);
+  ViewTreeState(
+      ViewRegistry* registry,
+      mojo::ui::ViewTreePtr view_tree,
+      mojo::ui::ViewTreeTokenPtr view_tree_token,
+      mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request,
+      const std::string& label);
   ~ViewTreeState();
 
   base::WeakPtr<ViewTreeState> GetWeakPtr() {
@@ -35,7 +40,7 @@
   }
 
   // Gets the view tree interface, never null.
-  // Caller does not obtain ownership of the view.
+  // Caller does not obtain ownership of the view tree.
   mojo::ui::ViewTree* view_tree() const { return view_tree_.get(); }
 
   // Gets the token used to refer to this view tree globally.
@@ -44,30 +49,14 @@
     return view_tree_token_.get();
   }
 
-  // Sets the associated host implementation and takes ownership of it.
-  void set_view_tree_host(mojo::ui::ViewTreeHost* host) {
-    view_tree_host_.reset(host);
-  }
+  // Gets the root of the view tree, or null if there is no root.
+  ViewStub* root() const { return root_.get(); }
 
-  // Sets the connection error handler for the view.
-  void set_view_tree_connection_error_handler(const base::Closure& handler) {
-    view_tree_.set_connection_error_handler(handler);
-  }
+  // Links the root of the view tree.
+  void LinkRoot(uint32_t key, std::unique_ptr<ViewStub> root);
 
-  // Gets the root of the view tree, or null if it is unavailable.
-  ViewState* root() const { return root_; }
-
-  // Sets the root of the view tree.  Must not be null.
-  // The view specified as the new root must not have any parents.
-  void SetRoot(ViewState* root, uint32_t key);
-
-  // Resets the root view to null.
-  void ResetRoot();
-
-  // True if the client previously set but has not yet explicitly unset
-  // the root, independent of whether it is currently available.
-  bool explicit_root() const { return explicit_root_; }
-  void set_explicit_root(bool value) { explicit_root_ = value; }
+  // Unlinks the root of the view tree and returns it.
+  std::unique_ptr<ViewStub> UnlinkRoot();
 
   // True if there is a pending layout request.
   bool layout_request_pending() const { return layout_request_pending_; }
@@ -79,18 +68,21 @@
   bool layout_request_issued() const { return layout_request_issued_; }
   void set_layout_request_issued(bool value) { layout_request_issued_ = value; }
 
-  const std::string& label() { return label_; }
-  const std::string& FormattedLabel();
+  const std::string& label() const { return label_; }
+  const std::string& FormattedLabel() const;
 
  private:
   mojo::ui::ViewTreePtr view_tree_;
   mojo::ui::ViewTreeTokenPtr view_tree_token_;
+
   const std::string label_;
-  std::string formatted_label_cache_;
+  mutable std::string formatted_label_cache_;
+
+  std::unique_ptr<ViewTreeHostImpl> impl_;
+  mojo::Binding<mojo::ui::ViewTreeHost> host_binding_;
 
   std::unique_ptr<mojo::ui::ViewTreeHost> view_tree_host_;
-  ViewState* root_ = nullptr;
-  bool explicit_root_ = false;
+  std::unique_ptr<ViewStub> root_;
   bool layout_request_pending_ = false;
   bool layout_request_issued_ = false;