Move application_manager from /mojo to /shell.

application_manager is an implementation detail of the shell.

BUG=430984
R=jamesr@chromium.org

Review URL: https://codereview.chromium.org/814273005
diff --git a/shell/BUILD.gn b/shell/BUILD.gn
index d1bba63..63fcde4 100644
--- a/shell/BUILD.gn
+++ b/shell/BUILD.gn
@@ -35,6 +35,7 @@
   deps = [
     ":external_application_unittests",
     ":mojo_shell_tests",
+    "//shell/application_manager:mojo_application_manager_unittests",
   ]
 }
 
@@ -71,8 +72,8 @@
 
       deps += [
         ":jni_headers",
-        "//mojo/application_manager:application_manager",
         "//services/native_viewport:lib",
+        "//shell/application_manager",
         "//ui/gl",
       ]
     }
@@ -178,13 +179,13 @@
     "//base/third_party/dynamic_annotations",
     "//base:base_static",
     "//mojo/application",
-    "//mojo/application_manager",
     "//mojo/common",
     "//mojo/common:tracing_impl",
     "//mojo/edk/system",
     "//mojo/public/cpp/bindings",
     "//mojo/public/interfaces/application",
     "//mojo/services/network/public/interfaces",
+    "//shell/application_manager",
     "//shell/domain_socket",
     "//services/tracing:bindings",
     "//url",
@@ -424,12 +425,12 @@
     "//testing/gtest",
     "//net:test_support",
     "//url",
-    "//mojo/application_manager",
     "//mojo/common",
     "//mojo/edk/system",
     "//mojo/environment:chromium",
     "//mojo/public/cpp/bindings",
     "//services/test_service:bindings",
+    "//shell/application_manager",
   ]
 
   datadeps = [
@@ -458,8 +459,8 @@
     ":init",
     ":lib",
     "//base",
-    "//mojo/application_manager",
     "//mojo/edk/system",
+    "//shell/application_manager",
   ]
 }
 
@@ -479,10 +480,10 @@
     "//testing/gtest",
     "//url",
     "//mojo/application",
-    "//mojo/application_manager",
     "//mojo/common",
     "//mojo/edk/system",
     "//mojo/environment:chromium",
+    "//shell/application_manager",
     "//shell/domain_socket",
     "//shell/domain_socket:tests",
   ]
diff --git a/shell/android/android_handler_loader.h b/shell/android/android_handler_loader.h
index 19e7fa6..9360574 100644
--- a/shell/android/android_handler_loader.h
+++ b/shell/android/android_handler_loader.h
@@ -8,9 +8,9 @@
 #include "base/containers/scoped_ptr_hash_map.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
-#include "mojo/application_manager/application_loader.h"
 #include "mojo/public/cpp/application/application_impl.h"
 #include "shell/android/android_handler.h"
+#include "shell/application_manager/application_loader.h"
 
 namespace mojo {
 namespace shell {
diff --git a/shell/android/background_application_loader.cc b/shell/android/background_application_loader.cc
index 8e6d0f4..0f72c3c 100644
--- a/shell/android/background_application_loader.cc
+++ b/shell/android/background_application_loader.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/run_loop.h"
-#include "mojo/application_manager/application_manager.h"
+#include "shell/application_manager/application_manager.h"
 
 namespace mojo {
 
diff --git a/shell/android/background_application_loader.h b/shell/android/background_application_loader.h
index 5321d97..4650ed6 100644
--- a/shell/android/background_application_loader.h
+++ b/shell/android/background_application_loader.h
@@ -10,7 +10,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/simple_thread.h"
-#include "mojo/application_manager/application_loader.h"
+#include "shell/application_manager/application_loader.h"
 
 namespace mojo {
 
diff --git a/shell/android/mojo_main.cc b/shell/android/mojo_main.cc
index 06581ae..502a340 100644
--- a/shell/android/mojo_main.cc
+++ b/shell/android/mojo_main.cc
@@ -20,12 +20,12 @@
 #include "base/run_loop.h"
 #include "base/threading/simple_thread.h"
 #include "jni/MojoMain_jni.h"
-#include "mojo/application_manager/application_loader.h"
 #include "mojo/common/message_pump_mojo.h"
 #include "shell/android/android_handler_loader.h"
 #include "shell/android/background_application_loader.h"
 #include "shell/android/native_viewport_application_loader.h"
 #include "shell/android/ui_application_loader_android.h"
+#include "shell/application_manager/application_loader.h"
 #include "shell/command_line_util.h"
 #include "shell/context.h"
 #include "shell/init.h"
diff --git a/shell/android/native_viewport_application_loader.h b/shell/android/native_viewport_application_loader.h
index ecaca49..f5d53ea 100644
--- a/shell/android/native_viewport_application_loader.h
+++ b/shell/android/native_viewport_application_loader.h
@@ -5,12 +5,12 @@
 #ifndef MOJO_SHELL_ANDROID_NATIVE_VIEWPORT_APPLICATION_LOADER_H_
 #define MOJO_SHELL_ANDROID_NATIVE_VIEWPORT_APPLICATION_LOADER_H_
 
-#include "mojo/application_manager/application_loader.h"
 #include "mojo/public/cpp/application/application_delegate.h"
 #include "mojo/public/cpp/application/interface_factory.h"
 #include "mojo/services/gpu/public/interfaces/gpu.mojom.h"
 #include "mojo/services/native_viewport/public/interfaces/native_viewport.mojom.h"
 #include "services/gles2/gpu_impl.h"
+#include "shell/application_manager/application_loader.h"
 
 namespace mojo {
 
diff --git a/shell/android/ui_application_loader_android.cc b/shell/android/ui_application_loader_android.cc
index ca4ff8b..dca237c 100644
--- a/shell/android/ui_application_loader_android.cc
+++ b/shell/android/ui_application_loader_android.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
-#include "mojo/application_manager/application_manager.h"
+#include "shell/application_manager/application_manager.h"
 
 namespace mojo {
 
diff --git a/shell/android/ui_application_loader_android.h b/shell/android/ui_application_loader_android.h
index 7de34c7..26ac13b 100644
--- a/shell/android/ui_application_loader_android.h
+++ b/shell/android/ui_application_loader_android.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
-#include "mojo/application_manager/application_loader.h"
+#include "shell/application_manager/application_loader.h"
 
 namespace base {
 class MessageLoop;
diff --git a/shell/application_manager/BUILD.gn b/shell/application_manager/BUILD.gn
new file mode 100644
index 0000000..c6828d7
--- /dev/null
+++ b/shell/application_manager/BUILD.gn
@@ -0,0 +1,62 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+component("application_manager") {
+  output_name = "mojo_application_manager"
+  sources = [
+    "application_loader.cc",
+    "application_loader.h",
+    "application_manager.cc",
+    "application_manager.h",
+    "application_manager_export.h",
+    "shell_impl.cc",
+    "shell_impl.h",
+  ]
+
+  defines = [ "MOJO_APPLICATION_MANAGER_IMPLEMENTATION" ]
+
+  public_deps = [
+    "//base",
+    "//mojo/common",
+    "//mojo/public/interfaces/application:application",
+    "//mojo/services/network/public/interfaces",
+    "//url",
+  ]
+  deps = [
+    "//base/third_party/dynamic_annotations",
+    "//url",
+    "//mojo/edk/system",
+    "//mojo/environment:chromium",
+    "//mojo/public/cpp/application",
+    "//mojo/public/cpp/bindings",
+    "//mojo/services/content_handler/public/interfaces",
+  ]
+}
+
+test("mojo_application_manager_unittests") {
+  sources = [
+    "application_manager_unittest.cc",
+  ]
+
+  deps = [
+    ":application_manager",
+    ":test_bindings",
+    "//base",
+    "//mojo/application",
+    "//mojo/common",
+    "//mojo/edk/test:run_all_unittests",
+    "//mojo/environment:chromium",
+    "//mojo/public/cpp/bindings",
+    "//testing/gtest",
+    "//url",
+  ]
+}
+
+mojom("test_bindings") {
+  sources = [
+    "test.mojom",
+  ]
+}
diff --git a/shell/application_manager/application_loader.cc b/shell/application_manager/application_loader.cc
new file mode 100644
index 0000000..ea653a1
--- /dev/null
+++ b/shell/application_manager/application_loader.cc
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shell/application_manager/application_loader.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+
+namespace mojo {
+
+namespace {
+
+void NotReached(const GURL& url,
+                ScopedMessagePipeHandle shell_handle,
+                URLResponsePtr response) {
+  NOTREACHED();
+}
+
+}  // namespace
+
+ApplicationLoader::LoadCallback ApplicationLoader::SimpleLoadCallback() {
+  return base::Bind(&NotReached);
+}
+
+}  // namespace mojo
diff --git a/shell/application_manager/application_loader.h b/shell/application_manager/application_loader.h
new file mode 100644
index 0000000..7dffe0a
--- /dev/null
+++ b/shell/application_manager/application_loader.h
@@ -0,0 +1,58 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHELL_APPLICATION_MANAGER_APPLICATION_LOADER_H_
+#define SHELL_APPLICATION_MANAGER_APPLICATION_LOADER_H_
+
+#include "base/callback.h"
+#include "mojo/public/cpp/system/core.h"
+#include "mojo/services/network/public/interfaces/url_loader.mojom.h"
+#include "shell/application_manager/application_manager_export.h"
+#include "url/gurl.h"
+
+namespace mojo {
+
+class ApplicationManager;
+
+// Interface to allowing loading behavior to be established for schemes,
+// specific urls or as the default.
+// A ApplicationLoader is responsible to using whatever mechanism is appropriate
+// to load the application at url.
+// The handle to the shell is passed to that application so it can bind it to
+// a Shell instance. This will give the Application a way to connect to other
+// apps and services.
+class MOJO_APPLICATION_MANAGER_EXPORT ApplicationLoader {
+ public:
+  typedef base::Callback<
+      void(const GURL&, ScopedMessagePipeHandle, URLResponsePtr)> LoadCallback;
+  virtual ~ApplicationLoader() {}
+
+  // Returns a callback that will should never be called.
+  static LoadCallback SimpleLoadCallback();
+
+  // Load the application named |url|. Applications can be loaded two ways:
+  //
+  // 1. |url| can refer directly to a Mojo application. In this case,
+  //    shell_handle should be used to implement the mojo.Application interface.
+  //
+  // 2. |url| can refer to some content that can be handled by some other Mojo
+  //    application. In this case, call callbacks and specify the URL of the
+  //    application that should handle the content.  The specified application
+  //    must implement the mojo.ContentHandler interface.
+  virtual void Load(ApplicationManager* application_manager,
+                    const GURL& url,
+                    ScopedMessagePipeHandle shell_handle,
+                    LoadCallback callback) = 0;
+
+  // Called when the Application exits.
+  virtual void OnApplicationError(ApplicationManager* manager,
+                                  const GURL& url) = 0;
+
+ protected:
+  ApplicationLoader() {}
+};
+
+}  // namespace mojo
+
+#endif  // SHELL_APPLICATION_MANAGER_APPLICATION_LOADER_H_
diff --git a/shell/application_manager/application_manager.cc b/shell/application_manager/application_manager.cc
new file mode 100644
index 0000000..2ead72e
--- /dev/null
+++ b/shell/application_manager/application_manager.cc
@@ -0,0 +1,275 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shell/application_manager/application_manager.h"
+
+#include <stdio.h>
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "mojo/public/cpp/application/connect.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/error_handler.h"
+#include "mojo/public/interfaces/application/shell.mojom.h"
+#include "mojo/services/content_handler/public/interfaces/content_handler.mojom.h"
+
+namespace mojo {
+
+namespace {
+// Used by TestAPI.
+bool has_created_instance = false;
+
+class StubServiceProvider : public InterfaceImpl<ServiceProvider> {
+ public:
+  ServiceProvider* GetRemoteServiceProvider() { return client(); }
+
+ private:
+  void ConnectToService(const String& service_name,
+                        ScopedMessagePipeHandle client_handle) override {}
+};
+
+}  // namespace
+
+
+ApplicationManager::Delegate::~Delegate() {
+}
+
+void ApplicationManager::Delegate::OnApplicationError(const GURL& url) {
+  LOG(ERROR) << "Communication error with application: " << url.spec();
+}
+
+GURL ApplicationManager::Delegate::ResolveURL(const GURL& url) {
+  return url;
+}
+
+class ApplicationManager::ContentHandlerConnection : public ErrorHandler {
+ public:
+  ContentHandlerConnection(ApplicationManager* manager,
+                           const GURL& content_handler_url)
+      : manager_(manager), content_handler_url_(content_handler_url) {
+    ServiceProviderPtr services;
+    manager->ConnectToApplication(content_handler_url, GURL(),
+                                  GetProxy(&services), nullptr);
+    mojo::ConnectToService(services.get(), &content_handler_);
+    content_handler_.set_error_handler(this);
+  }
+
+  ContentHandler* content_handler() { return content_handler_.get(); }
+
+  GURL content_handler_url() { return content_handler_url_; }
+
+ private:
+  // ErrorHandler implementation:
+  void OnConnectionError() override { manager_->OnContentHandlerError(this); }
+
+  ApplicationManager* manager_;
+  GURL content_handler_url_;
+  ContentHandlerPtr content_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(ContentHandlerConnection);
+};
+
+// static
+ApplicationManager::TestAPI::TestAPI(ApplicationManager* manager)
+    : manager_(manager) {
+}
+
+ApplicationManager::TestAPI::~TestAPI() {
+}
+
+bool ApplicationManager::TestAPI::HasCreatedInstance() {
+  return has_created_instance;
+}
+
+bool ApplicationManager::TestAPI::HasFactoryForURL(const GURL& url) const {
+  return manager_->url_to_shell_impl_.find(url) !=
+         manager_->url_to_shell_impl_.end();
+}
+
+ApplicationManager::ApplicationManager(Delegate* delegate)
+    : delegate_(delegate),
+      weak_ptr_factory_(this) {
+}
+
+ApplicationManager::~ApplicationManager() {
+  STLDeleteValues(&url_to_content_handler_);
+  TerminateShellConnections();
+  STLDeleteValues(&url_to_loader_);
+  STLDeleteValues(&scheme_to_loader_);
+}
+
+void ApplicationManager::TerminateShellConnections() {
+  STLDeleteValues(&url_to_shell_impl_);
+}
+
+void ApplicationManager::ConnectToApplication(
+    const GURL& requested_url,
+    const GURL& requestor_url,
+    InterfaceRequest<ServiceProvider> services,
+    ServiceProviderPtr exposed_services) {
+  DCHECK(requested_url.is_valid());
+  ApplicationLoader* loader = GetLoaderForURL(requested_url,
+                                              DONT_INCLUDE_DEFAULT_LOADER);
+  if (loader) {
+    ConnectToApplicationImpl(requested_url, requested_url, requestor_url,
+                             services.Pass(), exposed_services.Pass(), loader);
+    return;
+  }
+
+  GURL resolved_url = delegate_->ResolveURL(requested_url);
+  loader = GetLoaderForURL(resolved_url, INCLUDE_DEFAULT_LOADER);
+  if (loader) {
+    ConnectToApplicationImpl(requested_url, resolved_url, requestor_url,
+                             services.Pass(), exposed_services.Pass(), loader);
+    return;
+  }
+
+  LOG(WARNING) << "Could not find loader to load application: "
+               << requested_url.spec();
+}
+
+void ApplicationManager::ConnectToApplicationImpl(
+    const GURL& requested_url,
+    const GURL& resolved_url,
+    const GURL& requestor_url,
+    InterfaceRequest<ServiceProvider> services,
+    ServiceProviderPtr exposed_services,
+    ApplicationLoader* loader) {
+  ShellImpl* shell = nullptr;
+  URLToShellImplMap::const_iterator shell_it =
+      url_to_shell_impl_.find(resolved_url);
+  if (shell_it != url_to_shell_impl_.end()) {
+    shell = shell_it->second;
+  } else {
+    MessagePipe pipe;
+    shell =
+        new ShellImpl(pipe.handle0.Pass(), this, requested_url, resolved_url);
+    url_to_shell_impl_[resolved_url] = shell;
+    shell->client()->Initialize(GetArgsForURL(requested_url));
+
+    loader->Load(this, resolved_url, pipe.handle1.Pass(),
+                 base::Bind(&ApplicationManager::LoadWithContentHandler,
+                            weak_ptr_factory_.GetWeakPtr()));
+  }
+  ConnectToClient(shell, resolved_url, requestor_url, services.Pass(),
+                  exposed_services.Pass());
+}
+
+void ApplicationManager::ConnectToClient(
+    ShellImpl* shell_impl,
+    const GURL& url,
+    const GURL& requestor_url,
+    InterfaceRequest<ServiceProvider> services,
+    ServiceProviderPtr exposed_services) {
+  shell_impl->ConnectToClient(requestor_url, services.Pass(),
+                              exposed_services.Pass());
+}
+
+void ApplicationManager::RegisterExternalApplication(
+    const GURL& url,
+    ScopedMessagePipeHandle shell_handle) {
+  ShellImpl* shell_impl = new ShellImpl(shell_handle.Pass(), this, url, url);
+  url_to_shell_impl_[url] = shell_impl;
+  shell_impl->client()->Initialize(GetArgsForURL(url));
+}
+
+void ApplicationManager::LoadWithContentHandler(
+    const GURL& content_handler_url,
+    ScopedMessagePipeHandle shell_handle,
+    URLResponsePtr url_response) {
+  ContentHandlerConnection* connection = NULL;
+  URLToContentHandlerMap::iterator iter =
+      url_to_content_handler_.find(content_handler_url);
+  if (iter != url_to_content_handler_.end()) {
+    connection = iter->second;
+  } else {
+    connection = new ContentHandlerConnection(this, content_handler_url);
+    url_to_content_handler_[content_handler_url] = connection;
+  }
+
+  connection->content_handler()->StartApplication(
+      MakeProxy<Shell>(shell_handle.Pass()), url_response.Pass());
+}
+
+void ApplicationManager::SetLoaderForURL(scoped_ptr<ApplicationLoader> loader,
+                                         const GURL& url) {
+  URLToLoaderMap::iterator it = url_to_loader_.find(url);
+  if (it != url_to_loader_.end())
+    delete it->second;
+  url_to_loader_[url] = loader.release();
+}
+
+void ApplicationManager::SetLoaderForScheme(
+    scoped_ptr<ApplicationLoader> loader,
+    const std::string& scheme) {
+  SchemeToLoaderMap::iterator it = scheme_to_loader_.find(scheme);
+  if (it != scheme_to_loader_.end())
+    delete it->second;
+  scheme_to_loader_[scheme] = loader.release();
+}
+
+void ApplicationManager::SetArgsForURL(const std::vector<std::string>& args,
+                                       const GURL& url) {
+  url_to_args_[url] = args;
+}
+
+ApplicationLoader* ApplicationManager::GetLoaderForURL(
+    const GURL& url, IncludeDefaultLoader include_default_loader) {
+  auto url_it = url_to_loader_.find(url);
+  if (url_it != url_to_loader_.end())
+    return url_it->second;
+  auto scheme_it = scheme_to_loader_.find(url.scheme());
+  if (scheme_it != scheme_to_loader_.end())
+    return scheme_it->second;
+  if (include_default_loader == INCLUDE_DEFAULT_LOADER)
+    return default_loader_.get();
+  return NULL;
+}
+
+void ApplicationManager::OnShellImplError(ShellImpl* shell_impl) {
+  // Called from ~ShellImpl, so we do not need to call Destroy here.
+  const GURL url = shell_impl->url();
+  const GURL requested_url = shell_impl->requested_url();
+  // Remove the shell.
+  URLToShellImplMap::iterator it = url_to_shell_impl_.find(url);
+  DCHECK(it != url_to_shell_impl_.end());
+  delete it->second;
+  url_to_shell_impl_.erase(it);
+  ApplicationLoader* loader = GetLoaderForURL(requested_url,
+                                              INCLUDE_DEFAULT_LOADER);
+  if (loader)
+    loader->OnApplicationError(this, url);
+  delegate_->OnApplicationError(requested_url);
+}
+
+void ApplicationManager::OnContentHandlerError(
+    ContentHandlerConnection* content_handler) {
+  // Remove the mapping to the content handler.
+  auto it =
+      url_to_content_handler_.find(content_handler->content_handler_url());
+  DCHECK(it != url_to_content_handler_.end());
+  delete it->second;
+  url_to_content_handler_.erase(it);
+}
+
+ScopedMessagePipeHandle ApplicationManager::ConnectToServiceByName(
+    const GURL& application_url,
+    const std::string& interface_name) {
+  ServiceProviderPtr services;
+  ConnectToApplication(application_url, GURL(), GetProxy(&services), nullptr);
+  MessagePipe pipe;
+  services->ConnectToService(interface_name, pipe.handle1.Pass());
+  return pipe.handle0.Pass();
+}
+
+Array<String> ApplicationManager::GetArgsForURL(const GURL& url) {
+  URLToArgsMap::const_iterator args_it = url_to_args_.find(url);
+  if (args_it != url_to_args_.end())
+    return Array<String>::From(args_it->second);
+  return Array<String>();
+}
+}  // namespace mojo
diff --git a/shell/application_manager/application_manager.h b/shell/application_manager/application_manager.h
new file mode 100644
index 0000000..c420e51
--- /dev/null
+++ b/shell/application_manager/application_manager.h
@@ -0,0 +1,156 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHELL_APPLICATION_MANAGER_APPLICATION_MANAGER_H_
+#define SHELL_APPLICATION_MANAGER_APPLICATION_MANAGER_H_
+
+#include <map>
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/public/interfaces/application/service_provider.mojom.h"
+#include "shell/application_manager/application_loader.h"
+#include "shell/application_manager/application_manager_export.h"
+#include "shell/application_manager/shell_impl.h"
+#include "url/gurl.h"
+
+namespace mojo {
+
+class MOJO_APPLICATION_MANAGER_EXPORT ApplicationManager {
+ public:
+  class MOJO_APPLICATION_MANAGER_EXPORT Delegate {
+   public:
+    virtual ~Delegate();
+    // Send when the Application holding the handle on the other end of the
+    // Shell pipe goes away.
+    virtual void OnApplicationError(const GURL& url);
+    virtual GURL ResolveURL(const GURL& url);
+  };
+
+  // API for testing.
+  class MOJO_APPLICATION_MANAGER_EXPORT TestAPI {
+   public:
+    explicit TestAPI(ApplicationManager* manager);
+    ~TestAPI();
+
+    // Returns true if the shared instance has been created.
+    static bool HasCreatedInstance();
+    // Returns true if there is a ShellImpl for this URL.
+    bool HasFactoryForURL(const GURL& url) const;
+
+   private:
+    ApplicationManager* manager_;
+
+    DISALLOW_COPY_AND_ASSIGN(TestAPI);
+  };
+
+  explicit ApplicationManager(Delegate* delegate);
+  ~ApplicationManager();
+
+  // Loads a service if necessary and establishes a new client connection.
+  void ConnectToApplication(const GURL& application_url,
+                            const GURL& requestor_url,
+                            InterfaceRequest<ServiceProvider> services,
+                            ServiceProviderPtr exposed_services);
+
+  template <typename Interface>
+  inline void ConnectToService(const GURL& application_url,
+                               InterfacePtr<Interface>* ptr) {
+    ScopedMessagePipeHandle service_handle =
+        ConnectToServiceByName(application_url, Interface::Name_);
+    ptr->Bind(service_handle.Pass());
+  }
+
+  ScopedMessagePipeHandle ConnectToServiceByName(
+      const GURL& application_url,
+      const std::string& interface_name);
+
+  void RegisterExternalApplication(const GURL& application_url,
+                                   ScopedMessagePipeHandle shell);
+
+  // Sets the default Loader to be used if not overridden by SetLoaderForURL()
+  // or SetLoaderForScheme().
+  void set_default_loader(scoped_ptr<ApplicationLoader> loader) {
+    default_loader_ = loader.Pass();
+  }
+  // Sets a Loader to be used for a specific url.
+  void SetLoaderForURL(scoped_ptr<ApplicationLoader> loader, const GURL& url);
+  // Sets a Loader to be used for a specific url scheme.
+  void SetLoaderForScheme(scoped_ptr<ApplicationLoader> loader,
+                          const std::string& scheme);
+  // These strings will be passed to the Initialize() method when an
+  // Application is instantiated.
+  void SetArgsForURL(const std::vector<std::string>& args, const GURL& url);
+
+  // Destroys all Shell-ends of connections established with Applications.
+  // Applications connected by this ApplicationManager will observe pipe errors
+  // and have a chance to shutdown.
+  void TerminateShellConnections();
+
+  // Removes a ShellImpl when it encounters an error.
+  void OnShellImplError(ShellImpl* shell_impl);
+
+ private:
+  enum IncludeDefaultLoader {
+    INCLUDE_DEFAULT_LOADER,
+    DONT_INCLUDE_DEFAULT_LOADER,
+  };
+
+  class ContentHandlerConnection;
+
+  typedef std::map<std::string, ApplicationLoader*> SchemeToLoaderMap;
+  typedef std::map<GURL, ApplicationLoader*> URLToLoaderMap;
+  typedef std::map<GURL, ShellImpl*> URLToShellImplMap;
+  typedef std::map<GURL, ContentHandlerConnection*> URLToContentHandlerMap;
+  typedef std::map<GURL, std::vector<std::string> > URLToArgsMap;
+
+  void ConnectToApplicationImpl(const GURL& requested_url,
+                                const GURL& resolved_url,
+                                const GURL& requestor_url,
+                                InterfaceRequest<ServiceProvider> services,
+                                ServiceProviderPtr exposed_services,
+                                ApplicationLoader* loader);
+
+  void ConnectToClient(ShellImpl* shell_impl,
+                       const GURL& url,
+                       const GURL& requestor_url,
+                       InterfaceRequest<ServiceProvider> services,
+                       ServiceProviderPtr exposed_services);
+
+  void LoadWithContentHandler(const GURL& content_handler_url,
+                              ScopedMessagePipeHandle shell_handle,
+                              URLResponsePtr url_response);
+
+  // Return the appropriate loader for |url|. This can return NULL if there is
+  // no default loader configured.
+  ApplicationLoader* GetLoaderForURL(const GURL& url,
+                                     IncludeDefaultLoader fallback);
+
+  // Removes a ContentHandler when it encounters an error.
+  void OnContentHandlerError(ContentHandlerConnection* content_handler);
+
+  // Returns the arguments for the given url.
+  Array<String> GetArgsForURL(const GURL& url);
+
+  Delegate* delegate_;
+  // Loader management.
+  URLToLoaderMap url_to_loader_;
+  SchemeToLoaderMap scheme_to_loader_;
+  scoped_ptr<ApplicationLoader> default_loader_;
+
+  URLToShellImplMap url_to_shell_impl_;
+  URLToContentHandlerMap url_to_content_handler_;
+  URLToArgsMap url_to_args_;
+
+  base::WeakPtrFactory<ApplicationManager> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ApplicationManager);
+};
+
+}  // namespace mojo
+
+#endif  // SHELL_APPLICATION_MANAGER_APPLICATION_MANAGER_H_
diff --git a/shell/application_manager/application_manager_export.h b/shell/application_manager/application_manager_export.h
new file mode 100644
index 0000000..7b3f357
--- /dev/null
+++ b/shell/application_manager/application_manager_export.h
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHELL_APPLICATION_MANAGER_APPLICATION_MANAGER_EXPORT_H_
+#define SHELL_APPLICATION_MANAGER_APPLICATION_MANAGER_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(WIN32)
+
+#if defined(MOJO_APPLICATION_MANAGER_IMPLEMENTATION)
+#define MOJO_APPLICATION_MANAGER_EXPORT __declspec(dllexport)
+#else
+#define MOJO_APPLICATION_MANAGER_EXPORT __declspec(dllimport)
+#endif
+
+#else  // !defined(WIN32)
+
+#if defined(MOJO_APPLICATION_MANAGER_IMPLEMENTATION)
+#define MOJO_APPLICATION_MANAGER_EXPORT __attribute__((visibility("default")))
+#else
+#define MOJO_APPLICATION_MANAGER_EXPORT
+#endif
+
+#endif  // defined(WIN32)
+
+#else  // !defined(COMPONENT_BUILD)
+#define MOJO_APPLICATION_MANAGER_EXPORT
+#endif
+
+#endif  // SHELL_APPLICATION_MANAGER_APPLICATION_MANAGER_EXPORT_H_
diff --git a/shell/application_manager/application_manager_unittest.cc b/shell/application_manager/application_manager_unittest.cc
new file mode 100644
index 0000000..f1a09cd
--- /dev/null
+++ b/shell/application_manager/application_manager_unittest.cc
@@ -0,0 +1,673 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/public/cpp/application/application_connection.h"
+#include "mojo/public/cpp/application/application_delegate.h"
+#include "mojo/public/cpp/application/application_impl.h"
+#include "mojo/public/cpp/application/interface_factory.h"
+#include "mojo/public/interfaces/application/service_provider.mojom.h"
+#include "shell/application_manager/application_loader.h"
+#include "shell/application_manager/application_manager.h"
+#include "shell/application_manager/test.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+const char kTestURLString[] = "test:testService";
+const char kTestAURLString[] = "test:TestA";
+const char kTestBURLString[] = "test:TestB";
+
+struct TestContext {
+  TestContext() : num_impls(0), num_loader_deletes(0) {}
+  std::string last_test_string;
+  int num_impls;
+  int num_loader_deletes;
+};
+
+class QuitMessageLoopErrorHandler : public ErrorHandler {
+ public:
+  QuitMessageLoopErrorHandler() {}
+  ~QuitMessageLoopErrorHandler() override {}
+
+  // |ErrorHandler| implementation:
+  void OnConnectionError() override {
+    base::MessageLoop::current()->QuitWhenIdle();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(QuitMessageLoopErrorHandler);
+};
+
+class TestServiceImpl : public InterfaceImpl<TestService> {
+ public:
+  explicit TestServiceImpl(TestContext* context) : context_(context) {
+    ++context_->num_impls;
+  }
+
+  ~TestServiceImpl() override { --context_->num_impls; }
+
+  void OnConnectionError() override {
+    if (!base::MessageLoop::current()->is_running())
+      return;
+    base::MessageLoop::current()->Quit();
+    InterfaceImpl::OnConnectionError();
+  }
+
+  // TestService implementation:
+  void Test(const String& test_string) override {
+    context_->last_test_string = test_string;
+    client()->AckTest();
+  }
+
+ private:
+  TestContext* context_;
+};
+
+class TestClientImpl : public TestClient {
+ public:
+  explicit TestClientImpl(TestServicePtr service)
+      : service_(service.Pass()), quit_after_ack_(false) {
+    service_.set_client(this);
+  }
+
+  ~TestClientImpl() override { service_.reset(); }
+
+  void AckTest() override {
+    if (quit_after_ack_)
+      base::MessageLoop::current()->Quit();
+  }
+
+  void Test(const std::string& test_string) {
+    quit_after_ack_ = true;
+    service_->Test(test_string);
+  }
+
+ private:
+  TestServicePtr service_;
+  bool quit_after_ack_;
+  DISALLOW_COPY_AND_ASSIGN(TestClientImpl);
+};
+
+class TestApplicationLoader : public ApplicationLoader,
+                              public ApplicationDelegate,
+                              public InterfaceFactory<TestService> {
+ public:
+  TestApplicationLoader() : context_(NULL), num_loads_(0) {}
+
+  ~TestApplicationLoader() override {
+    if (context_)
+      ++context_->num_loader_deletes;
+    test_app_.reset(NULL);
+  }
+
+  void set_context(TestContext* context) { context_ = context; }
+  int num_loads() const { return num_loads_; }
+  const std::vector<std::string>& GetArgs() const { return test_app_->args(); }
+
+ private:
+  // ApplicationLoader implementation.
+  void Load(ApplicationManager* manager,
+            const GURL& url,
+            ScopedMessagePipeHandle shell_handle,
+            LoadCallback callback) override {
+    ++num_loads_;
+    test_app_.reset(new ApplicationImpl(this, shell_handle.Pass()));
+  }
+
+  void OnApplicationError(ApplicationManager* manager,
+                          const GURL& url) override {}
+
+  // ApplicationDelegate implementation.
+  bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
+    connection->AddService(this);
+    return true;
+  }
+
+  // InterfaceFactory implementation.
+  void Create(ApplicationConnection* connection,
+              InterfaceRequest<TestService> request) override {
+    BindToRequest(new TestServiceImpl(context_), &request);
+  }
+
+  scoped_ptr<ApplicationImpl> test_app_;
+  TestContext* context_;
+  int num_loads_;
+  DISALLOW_COPY_AND_ASSIGN(TestApplicationLoader);
+};
+
+class TesterContext {
+ public:
+  explicit TesterContext(base::MessageLoop* loop)
+      : num_b_calls_(0),
+        num_c_calls_(0),
+        num_a_deletes_(0),
+        num_b_deletes_(0),
+        num_c_deletes_(0),
+        tester_called_quit_(false),
+        a_called_quit_(false),
+        loop_(loop) {}
+
+  void IncrementNumBCalls() {
+    base::AutoLock lock(lock_);
+    num_b_calls_++;
+  }
+
+  void IncrementNumCCalls() {
+    base::AutoLock lock(lock_);
+    num_c_calls_++;
+  }
+
+  void IncrementNumADeletes() {
+    base::AutoLock lock(lock_);
+    num_a_deletes_++;
+  }
+
+  void IncrementNumBDeletes() {
+    base::AutoLock lock(lock_);
+    num_b_deletes_++;
+  }
+
+  void IncrementNumCDeletes() {
+    base::AutoLock lock(lock_);
+    num_c_deletes_++;
+  }
+
+  void set_tester_called_quit() {
+    base::AutoLock lock(lock_);
+    tester_called_quit_ = true;
+  }
+
+  void set_a_called_quit() {
+    base::AutoLock lock(lock_);
+    a_called_quit_ = true;
+  }
+
+  int num_b_calls() {
+    base::AutoLock lock(lock_);
+    return num_b_calls_;
+  }
+  int num_c_calls() {
+    base::AutoLock lock(lock_);
+    return num_c_calls_;
+  }
+  int num_a_deletes() {
+    base::AutoLock lock(lock_);
+    return num_a_deletes_;
+  }
+  int num_b_deletes() {
+    base::AutoLock lock(lock_);
+    return num_b_deletes_;
+  }
+  int num_c_deletes() {
+    base::AutoLock lock(lock_);
+    return num_c_deletes_;
+  }
+  bool tester_called_quit() {
+    base::AutoLock lock(lock_);
+    return tester_called_quit_;
+  }
+  bool a_called_quit() {
+    base::AutoLock lock(lock_);
+    return a_called_quit_;
+  }
+
+  void QuitSoon() {
+    loop_->PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
+  }
+
+ private:
+  // lock_ protects all members except for loop_ which must be unchanged for the
+  // lifetime of this class.
+  base::Lock lock_;
+  int num_b_calls_;
+  int num_c_calls_;
+  int num_a_deletes_;
+  int num_b_deletes_;
+  int num_c_deletes_;
+  bool tester_called_quit_;
+  bool a_called_quit_;
+
+  base::MessageLoop* loop_;
+};
+
+// Used to test that the requestor url will be correctly passed.
+class TestAImpl : public TestA {
+ public:
+  TestAImpl(ApplicationConnection* connection,
+            TesterContext* test_context,
+            InterfaceRequest<TestA> request)
+      : test_context_(test_context),
+        binding_(this, request.Pass()) {
+    connection->ConnectToApplication(kTestBURLString)->ConnectToService(&b_);
+  }
+  ~TestAImpl() override {
+    test_context_->IncrementNumADeletes();
+    if (base::MessageLoop::current()->is_running())
+      Quit();
+  }
+
+ private:
+  void CallB() override {
+    b_->B(base::Bind(&TestAImpl::Quit, base::Unretained(this)));
+  }
+
+  void CallCFromB() override {
+    b_->CallC(base::Bind(&TestAImpl::Quit, base::Unretained(this)));
+  }
+
+  void Quit() {
+    base::MessageLoop::current()->Quit();
+    test_context_->set_a_called_quit();
+    test_context_->QuitSoon();
+  }
+
+  TesterContext* test_context_;
+  TestBPtr b_;
+  Binding<TestA> binding_;
+};
+
+class TestBImpl : public InterfaceImpl<TestB> {
+ public:
+  TestBImpl(ApplicationConnection* connection, TesterContext* test_context)
+      : test_context_(test_context) {
+    connection->ConnectToService(&c_);
+  }
+
+  ~TestBImpl() override {
+    test_context_->IncrementNumBDeletes();
+    if (base::MessageLoop::current()->is_running())
+      base::MessageLoop::current()->Quit();
+    test_context_->QuitSoon();
+  }
+
+ private:
+  void B(const mojo::Callback<void()>& callback) override {
+    test_context_->IncrementNumBCalls();
+    callback.Run();
+  }
+
+  void CallC(const mojo::Callback<void()>& callback) override {
+    test_context_->IncrementNumBCalls();
+    c_->C(callback);
+  }
+
+  TesterContext* test_context_;
+  TestCPtr c_;
+};
+
+class TestCImpl : public InterfaceImpl<TestC> {
+ public:
+  TestCImpl(ApplicationConnection* connection, TesterContext* test_context)
+      : test_context_(test_context) {}
+
+  ~TestCImpl() override { test_context_->IncrementNumCDeletes(); }
+
+ private:
+  void C(const mojo::Callback<void()>& callback) override {
+    test_context_->IncrementNumCCalls();
+    callback.Run();
+  }
+  TesterContext* test_context_;
+};
+
+class Tester : public ApplicationDelegate,
+               public ApplicationLoader,
+               public InterfaceFactory<TestA>,
+               public InterfaceFactory<TestB>,
+               public InterfaceFactory<TestC> {
+ public:
+  Tester(TesterContext* context, const std::string& requestor_url)
+      : context_(context), requestor_url_(requestor_url) {}
+  ~Tester() override {}
+
+ private:
+  void Load(ApplicationManager* manager,
+            const GURL& url,
+            ScopedMessagePipeHandle shell_handle,
+            LoadCallback callback) override {
+    app_.reset(new ApplicationImpl(this, shell_handle.Pass()));
+  }
+
+  void OnApplicationError(ApplicationManager* manager,
+                          const GURL& url) override {}
+
+  bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
+    if (!requestor_url_.empty() &&
+        requestor_url_ != connection->GetRemoteApplicationURL()) {
+      context_->set_tester_called_quit();
+      context_->QuitSoon();
+      base::MessageLoop::current()->Quit();
+      return false;
+    }
+    // If we're coming from A, then add B, otherwise A.
+    if (connection->GetRemoteApplicationURL() == kTestAURLString)
+      connection->AddService<TestB>(this);
+    else
+      connection->AddService<TestA>(this);
+    return true;
+  }
+
+  bool ConfigureOutgoingConnection(ApplicationConnection* connection) override {
+    // If we're connecting to B, then add C.
+    if (connection->GetRemoteApplicationURL() == kTestBURLString)
+      connection->AddService<TestC>(this);
+    return true;
+  }
+
+  void Create(ApplicationConnection* connection,
+              InterfaceRequest<TestA> request) override {
+    a_bindings_.push_back(new TestAImpl(connection, context_, request.Pass()));
+  }
+
+  void Create(ApplicationConnection* connection,
+              InterfaceRequest<TestB> request) override {
+    BindToRequest(new TestBImpl(connection, context_), &request);
+  }
+
+  void Create(ApplicationConnection* connection,
+              InterfaceRequest<TestC> request) override {
+    BindToRequest(new TestCImpl(connection, context_), &request);
+  }
+
+  TesterContext* context_;
+  scoped_ptr<ApplicationImpl> app_;
+  std::string requestor_url_;
+  ScopedVector<TestAImpl> a_bindings_;
+};
+
+class TestDelegate : public ApplicationManager::Delegate {
+ public:
+  void AddMapping(const GURL& from, const GURL& to) {
+    mappings_[from] = to;
+  }
+
+  // ApplicationManager::Delegate
+  virtual GURL ResolveURL(const GURL& url) override {
+    auto it = mappings_.find(url);
+    if (it != mappings_.end())
+      return it->second;
+    return url;
+  }
+
+  virtual void OnApplicationError(const GURL& url) override {
+  }
+
+ private:
+  std::map<GURL, GURL> mappings_;
+};
+
+}  // namespace
+
+class ApplicationManagerTest : public testing::Test {
+ public:
+  ApplicationManagerTest() : tester_context_(&loop_) {}
+
+  ~ApplicationManagerTest() override {}
+
+  void SetUp() override {
+    application_manager_.reset(new ApplicationManager(&test_delegate_));
+    test_loader_ = new TestApplicationLoader;
+    test_loader_->set_context(&context_);
+    application_manager_->set_default_loader(
+        scoped_ptr<ApplicationLoader>(test_loader_));
+
+    TestServicePtr service_proxy;
+    application_manager_->ConnectToService(GURL(kTestURLString),
+                                           &service_proxy);
+    test_client_.reset(new TestClientImpl(service_proxy.Pass()));
+  }
+
+  void TearDown() override {
+    test_client_.reset(NULL);
+    application_manager_.reset(NULL);
+  }
+
+  void AddLoaderForURL(const GURL& url, const std::string& requestor_url) {
+    application_manager_->SetLoaderForURL(
+        make_scoped_ptr(new Tester(&tester_context_, requestor_url)), url);
+  }
+
+  bool HasFactoryForTestURL() {
+    ApplicationManager::TestAPI manager_test_api(application_manager_.get());
+    return manager_test_api.HasFactoryForURL(GURL(kTestURLString));
+  }
+
+ protected:
+  base::ShadowingAtExitManager at_exit_;
+  TestDelegate test_delegate_;
+  TestApplicationLoader* test_loader_;
+  TesterContext tester_context_;
+  TestContext context_;
+  base::MessageLoop loop_;
+  scoped_ptr<TestClientImpl> test_client_;
+  scoped_ptr<ApplicationManager> application_manager_;
+  DISALLOW_COPY_AND_ASSIGN(ApplicationManagerTest);
+};
+
+TEST_F(ApplicationManagerTest, Basic) {
+  test_client_->Test("test");
+  loop_.Run();
+  EXPECT_EQ(std::string("test"), context_.last_test_string);
+}
+
+// Confirm that no arguments are sent to an application by default.
+TEST_F(ApplicationManagerTest, NoArgs) {
+  ApplicationManager am(&test_delegate_);
+  GURL test_url("test:test");
+  TestApplicationLoader* loader = new TestApplicationLoader;
+  loader->set_context(&context_);
+  am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(loader), test_url);
+  TestServicePtr test_service;
+  am.ConnectToService(test_url, &test_service);
+  TestClientImpl test_client(test_service.Pass());
+  test_client.Test("test");
+  loop_.Run();
+  std::vector<std::string> app_args = loader->GetArgs();
+  EXPECT_EQ(0U, app_args.size());
+}
+
+// Confirm that arguments are sent to an application.
+TEST_F(ApplicationManagerTest, Args) {
+  ApplicationManager am(&test_delegate_);
+  GURL test_url("test:test");
+  std::vector<std::string> args;
+  args.push_back("test_arg1");
+  args.push_back("test_arg2");
+  am.SetArgsForURL(args, test_url);
+  TestApplicationLoader* loader = new TestApplicationLoader;
+  loader->set_context(&context_);
+  am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(loader), test_url);
+  TestServicePtr test_service;
+  am.ConnectToService(test_url, &test_service);
+  TestClientImpl test_client(test_service.Pass());
+  test_client.Test("test");
+  loop_.Run();
+  std::vector<std::string> app_args = loader->GetArgs();
+  ASSERT_EQ(args.size(), app_args.size());
+  EXPECT_EQ(args[0], app_args[0]);
+  EXPECT_EQ(args[1], app_args[1]);
+}
+
+TEST_F(ApplicationManagerTest, ClientError) {
+  test_client_->Test("test");
+  EXPECT_TRUE(HasFactoryForTestURL());
+  loop_.Run();
+  EXPECT_EQ(1, context_.num_impls);
+  test_client_.reset(NULL);
+  loop_.Run();
+  EXPECT_EQ(0, context_.num_impls);
+  EXPECT_TRUE(HasFactoryForTestURL());
+}
+
+TEST_F(ApplicationManagerTest, Deletes) {
+  {
+    ApplicationManager am(&test_delegate_);
+    TestApplicationLoader* default_loader = new TestApplicationLoader;
+    default_loader->set_context(&context_);
+    TestApplicationLoader* url_loader1 = new TestApplicationLoader;
+    TestApplicationLoader* url_loader2 = new TestApplicationLoader;
+    url_loader1->set_context(&context_);
+    url_loader2->set_context(&context_);
+    TestApplicationLoader* scheme_loader1 = new TestApplicationLoader;
+    TestApplicationLoader* scheme_loader2 = new TestApplicationLoader;
+    scheme_loader1->set_context(&context_);
+    scheme_loader2->set_context(&context_);
+    am.set_default_loader(scoped_ptr<ApplicationLoader>(default_loader));
+    am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(url_loader1),
+                       GURL("test:test1"));
+    am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(url_loader2),
+                       GURL("test:test1"));
+    am.SetLoaderForScheme(scoped_ptr<ApplicationLoader>(scheme_loader1),
+                          "test");
+    am.SetLoaderForScheme(scoped_ptr<ApplicationLoader>(scheme_loader2),
+                          "test");
+  }
+  EXPECT_EQ(5, context_.num_loader_deletes);
+}
+
+// Confirm that both urls and schemes can have their loaders explicitly set.
+TEST_F(ApplicationManagerTest, SetLoaders) {
+  TestApplicationLoader* default_loader = new TestApplicationLoader;
+  TestApplicationLoader* url_loader = new TestApplicationLoader;
+  TestApplicationLoader* scheme_loader = new TestApplicationLoader;
+  application_manager_->set_default_loader(
+      scoped_ptr<ApplicationLoader>(default_loader));
+  application_manager_->SetLoaderForURL(
+      scoped_ptr<ApplicationLoader>(url_loader), GURL("test:test1"));
+  application_manager_->SetLoaderForScheme(
+      scoped_ptr<ApplicationLoader>(scheme_loader), "test");
+
+  // test::test1 should go to url_loader.
+  TestServicePtr test_service;
+  application_manager_->ConnectToService(GURL("test:test1"), &test_service);
+  EXPECT_EQ(1, url_loader->num_loads());
+  EXPECT_EQ(0, scheme_loader->num_loads());
+  EXPECT_EQ(0, default_loader->num_loads());
+
+  // test::test2 should go to scheme loader.
+  application_manager_->ConnectToService(GURL("test:test2"), &test_service);
+  EXPECT_EQ(1, url_loader->num_loads());
+  EXPECT_EQ(1, scheme_loader->num_loads());
+  EXPECT_EQ(0, default_loader->num_loads());
+
+  // http::test1 should go to default loader.
+  application_manager_->ConnectToService(GURL("http:test1"), &test_service);
+  EXPECT_EQ(1, url_loader->num_loads());
+  EXPECT_EQ(1, scheme_loader->num_loads());
+  EXPECT_EQ(1, default_loader->num_loads());
+}
+
+// Confirm that the url of a service is correctly passed to another service that
+// it loads.
+TEST_F(ApplicationManagerTest, ACallB) {
+  // Any url can load a.
+  AddLoaderForURL(GURL(kTestAURLString), std::string());
+
+  // Only a can load b.
+  AddLoaderForURL(GURL(kTestBURLString), kTestAURLString);
+
+  TestAPtr a;
+  application_manager_->ConnectToService(GURL(kTestAURLString), &a);
+  a->CallB();
+  loop_.Run();
+  EXPECT_EQ(1, tester_context_.num_b_calls());
+  EXPECT_TRUE(tester_context_.a_called_quit());
+}
+
+// A calls B which calls C.
+TEST_F(ApplicationManagerTest, BCallC) {
+  // Any url can load a.
+  AddLoaderForURL(GURL(kTestAURLString), std::string());
+
+  // Only a can load b.
+  AddLoaderForURL(GURL(kTestBURLString), kTestAURLString);
+
+  TestAPtr a;
+  application_manager_->ConnectToService(GURL(kTestAURLString), &a);
+  a->CallCFromB();
+  loop_.Run();
+
+  EXPECT_EQ(1, tester_context_.num_b_calls());
+  EXPECT_EQ(1, tester_context_.num_c_calls());
+  EXPECT_TRUE(tester_context_.a_called_quit());
+}
+
+// Confirm that a service impl will be deleted if the app that connected to
+// it goes away.
+TEST_F(ApplicationManagerTest, BDeleted) {
+  AddLoaderForURL(GURL(kTestAURLString), std::string());
+  AddLoaderForURL(GURL(kTestBURLString), std::string());
+
+  TestAPtr a;
+  application_manager_->ConnectToService(GURL(kTestAURLString), &a);
+
+  a->CallB();
+  loop_.Run();
+
+  // Kills the a app.
+  application_manager_->SetLoaderForURL(scoped_ptr<ApplicationLoader>(),
+                                        GURL(kTestAURLString));
+  loop_.Run();
+
+  EXPECT_EQ(1, tester_context_.num_b_deletes());
+}
+
+// Confirm that the url of a service is correctly passed to another service that
+// it loads, and that it can be rejected.
+TEST_F(ApplicationManagerTest, ANoLoadB) {
+  // Any url can load a.
+  AddLoaderForURL(GURL(kTestAURLString), std::string());
+
+  // Only c can load b, so this will fail.
+  AddLoaderForURL(GURL(kTestBURLString), "test:TestC");
+
+  TestAPtr a;
+  application_manager_->ConnectToService(GURL(kTestAURLString), &a);
+  a->CallB();
+  loop_.Run();
+  EXPECT_EQ(0, tester_context_.num_b_calls());
+
+  EXPECT_FALSE(tester_context_.a_called_quit());
+  EXPECT_TRUE(tester_context_.tester_called_quit());
+}
+
+TEST_F(ApplicationManagerTest, NoServiceNoLoad) {
+  AddLoaderForURL(GURL(kTestAURLString), std::string());
+
+  // There is no TestC service implementation registered with
+  // ApplicationManager, so this cannot succeed (but also shouldn't crash).
+  TestCPtr c;
+  application_manager_->ConnectToService(GURL(kTestAURLString), &c);
+  QuitMessageLoopErrorHandler quitter;
+  c.set_error_handler(&quitter);
+
+  loop_.Run();
+  EXPECT_TRUE(c.encountered_error());
+}
+
+TEST_F(ApplicationManagerTest, MappedURLsShouldNotCauseDuplicateLoad) {
+  test_delegate_.AddMapping(GURL("foo:foo2"), GURL("foo:foo"));
+  // 1 because ApplicationManagerTest connects once at startup.
+  EXPECT_EQ(1, test_loader_->num_loads());
+
+  TestServicePtr test_service;
+  application_manager_->ConnectToService(GURL("foo:foo"), &test_service);
+  EXPECT_EQ(2, test_loader_->num_loads());
+
+  TestServicePtr test_service2;
+  application_manager_->ConnectToService(GURL("foo:foo2"), &test_service2);
+  EXPECT_EQ(2, test_loader_->num_loads());
+
+  TestServicePtr test_service3;
+  application_manager_->ConnectToService(GURL("bar:bar"), &test_service2);
+  EXPECT_EQ(3, test_loader_->num_loads());
+}
+
+}  // namespace mojo
diff --git a/shell/application_manager/shell_impl.cc b/shell/application_manager/shell_impl.cc
new file mode 100644
index 0000000..0d2b59d
--- /dev/null
+++ b/shell/application_manager/shell_impl.cc
@@ -0,0 +1,66 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shell/application_manager/shell_impl.h"
+
+#include "mojo/common/common_type_converters.h"
+#include "mojo/services/content_handler/public/interfaces/content_handler.mojom.h"
+#include "shell/application_manager/application_manager.h"
+
+namespace mojo {
+
+ShellImpl::ShellImpl(ScopedMessagePipeHandle handle,
+                     ApplicationManager* manager,
+                     const GURL& requested_url,
+                     const GURL& url)
+    : ShellImpl(manager, requested_url, url) {
+  binding_.Bind(handle.Pass());
+}
+
+ShellImpl::ShellImpl(ShellPtr* ptr,
+                     ApplicationManager* manager,
+                     const GURL& requested_url,
+                     const GURL& url)
+    : ShellImpl(manager, requested_url, url) {
+  binding_.Bind(ptr);
+}
+
+ShellImpl::~ShellImpl() {
+}
+
+void ShellImpl::ConnectToClient(const GURL& requestor_url,
+                                InterfaceRequest<ServiceProvider> services,
+                                ServiceProviderPtr exposed_services) {
+  client()->AcceptConnection(String::From(requestor_url), services.Pass(),
+                             exposed_services.Pass());
+}
+
+ShellImpl::ShellImpl(ApplicationManager* manager,
+                     const GURL& requested_url,
+                     const GURL& url)
+    : manager_(manager),
+      requested_url_(requested_url),
+      url_(url),
+      binding_(this) {
+  binding_.set_error_handler(this);
+}
+
+// Shell implementation:
+void ShellImpl::ConnectToApplication(const String& app_url,
+                                     InterfaceRequest<ServiceProvider> services,
+                                     ServiceProviderPtr exposed_services) {
+  GURL app_gurl(app_url);
+  if (!app_gurl.is_valid()) {
+    LOG(ERROR) << "Error: invalid URL: " << app_url;
+    return;
+  }
+  manager_->ConnectToApplication(app_gurl, url_, services.Pass(),
+                                 exposed_services.Pass());
+}
+
+void ShellImpl::OnConnectionError() {
+  manager_->OnShellImplError(this);
+}
+
+}  // namespace mojo
diff --git a/shell/application_manager/shell_impl.h b/shell/application_manager/shell_impl.h
new file mode 100644
index 0000000..ef4de83
--- /dev/null
+++ b/shell/application_manager/shell_impl.h
@@ -0,0 +1,62 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHELL_APPLICATION_MANAGER_SHELL_IMPL_H_
+#define SHELL_APPLICATION_MANAGER_SHELL_IMPL_H_
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/error_handler.h"
+#include "mojo/public/interfaces/application/application.mojom.h"
+#include "mojo/public/interfaces/application/shell.mojom.h"
+#include "url/gurl.h"
+
+namespace mojo {
+class ApplicationManager;
+
+class ShellImpl : public Shell, public ErrorHandler {
+ public:
+  ShellImpl(ScopedMessagePipeHandle handle,
+            ApplicationManager* manager,
+            const GURL& requested_url,
+            const GURL& url);
+
+  ShellImpl(ShellPtr* ptr,
+            ApplicationManager* manager,
+            const GURL& requested_url,
+            const GURL& url);
+
+  ~ShellImpl() override;
+
+  void ConnectToClient(const GURL& requestor_url,
+                       InterfaceRequest<ServiceProvider> services,
+                       ServiceProviderPtr exposed_services);
+
+  Application* client() { return binding_.client(); }
+  const GURL& url() const { return url_; }
+  const GURL& requested_url() const { return requested_url_; }
+
+ private:
+  ShellImpl(ApplicationManager* manager,
+            const GURL& requested_url,
+            const GURL& url);
+
+  // Shell implementation:
+  void ConnectToApplication(const String& app_url,
+                            InterfaceRequest<ServiceProvider> services,
+                            ServiceProviderPtr exposed_services) override;
+
+  // ErrorHandler implementation:
+  void OnConnectionError() override;
+
+  ApplicationManager* const manager_;
+  const GURL requested_url_;
+  const GURL url_;
+  Binding<Shell> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellImpl);
+};
+
+}  // namespace mojo
+
+#endif  // SHELL_APPLICATION_MANAGER_SHELL_IMPL_H_
diff --git a/shell/application_manager/test.mojom b/shell/application_manager/test.mojom
new file mode 100644
index 0000000..2912eec
--- /dev/null
+++ b/shell/application_manager/test.mojom
@@ -0,0 +1,28 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module mojo;
+
+[Client=TestClient]
+interface TestService {
+  Test(string test_string);
+};
+
+interface TestClient {
+  AckTest();
+};
+
+interface TestA {
+  CallB();
+  CallCFromB();
+};
+
+interface TestB {
+  B() => ();
+  CallC() => ();
+};
+
+interface TestC {
+  C() => ();
+};
diff --git a/shell/context.cc b/shell/context.cc
index 76a9076..d3a8613 100644
--- a/shell/context.cc
+++ b/shell/context.cc
@@ -16,8 +16,6 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
-#include "mojo/application_manager/application_loader.h"
-#include "mojo/application_manager/application_manager.h"
 #include "mojo/common/tracing_impl.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/simple_platform_support.h"
@@ -25,6 +23,8 @@
 #include "mojo/public/cpp/application/application_delegate.h"
 #include "mojo/public/cpp/application/application_impl.h"
 #include "services/tracing/tracing.mojom.h"
+#include "shell/application_manager/application_loader.h"
+#include "shell/application_manager/application_manager.h"
 #include "shell/dynamic_application_loader.h"
 #include "shell/external_application_listener.h"
 #include "shell/in_process_dynamic_service_runner.h"
diff --git a/shell/context.h b/shell/context.h
index 605719a..ab30f14 100644
--- a/shell/context.h
+++ b/shell/context.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/macros.h"
-#include "mojo/application_manager/application_manager.h"
+#include "shell/application_manager/application_manager.h"
 #include "shell/mojo_url_resolver.h"
 #include "shell/task_runners.h"
 
diff --git a/shell/dynamic_application_loader.h b/shell/dynamic_application_loader.h
index e0c553a..7780b78 100644
--- a/shell/dynamic_application_loader.h
+++ b/shell/dynamic_application_loader.h
@@ -11,9 +11,9 @@
 #include "base/macros.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
-#include "mojo/application_manager/application_loader.h"
 #include "mojo/public/cpp/system/core.h"
 #include "mojo/services/network/public/interfaces/network_service.mojom.h"
+#include "shell/application_manager/application_loader.h"
 #include "shell/dynamic_service_runner.h"
 #include "url/gurl.h"
 
diff --git a/shell/external_application_listener_unittest.cc b/shell/external_application_listener_unittest.cc
index f8e7316..ebc1a65 100644
--- a/shell/external_application_listener_unittest.cc
+++ b/shell/external_application_listener_unittest.cc
@@ -8,12 +8,12 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/threading/thread.h"
-#include "mojo/application_manager/application_loader.h"
-#include "mojo/application_manager/application_manager.h"
 #include "mojo/common/common_type_converters.h"
 #include "mojo/public/interfaces/application/application.mojom.h"
 #include "mojo/public/interfaces/application/service_provider.mojom.h"
 #include "mojo/public/interfaces/application/shell.mojom.h"
+#include "shell/application_manager/application_loader.h"
+#include "shell/application_manager/application_manager.h"
 #include "shell/domain_socket/net_errors.h"
 #include "shell/domain_socket/test_completion_callback.h"
 #include "shell/domain_socket/unix_domain_client_socket_posix.h"
diff --git a/shell/shell_test_helper.h b/shell/shell_test_helper.h
index 5d6cb5e..4a29818 100644
--- a/shell/shell_test_helper.h
+++ b/shell/shell_test_helper.h
@@ -8,7 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
-#include "mojo/application_manager/application_loader.h"
+#include "shell/application_manager/application_loader.h"
 #include "shell/context.h"
 
 class GURL;