Clone of chromium aad1ce808763f59c7a3753e08f1500a104ecc6fd refs/remotes/origin/HEAD
diff --git a/mojo/application_manager/BUILD.gn b/mojo/application_manager/BUILD.gn
new file mode 100644
index 0000000..22c0edd
--- /dev/null
+++ b/mojo/application_manager/BUILD.gn
@@ -0,0 +1,64 @@
+# 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")
+
+# GYP version: mojo.gyp:mojo_application_manager
+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",
+    "background_shell_application_loader.cc",
+    "background_shell_application_loader.h",
+  ]
+
+  defines = [
+    "MOJO_APPLICATION_MANAGER_IMPLEMENTATION",
+  ]
+
+  public_deps = [
+    "//base",
+    "//mojo/common",
+    "//mojo/public/interfaces/application:application",
+    "//mojo/services/public/interfaces/network:network",
+    "//url",
+  ]
+  deps = [
+    "//base/third_party/dynamic_annotations",
+    "//net",
+    "//url",
+    "//mojo/edk/system",
+    "//mojo/environment:chromium",
+    "//mojo/services/public/interfaces/content_handler:content_handler",
+  ]
+}
+
+# GYP version: mojo.gyp:mojo_application_manager_unittests
+test("mojo_application_manager_unittests") {
+  sources = [
+    "application_manager_unittest.cc",
+    "background_shell_application_loader_unittest.cc",
+  ]
+
+  deps = [
+    ":application_manager",
+    ":test_bindings",
+    "//base",
+    "//mojo/application",
+    "//mojo/common",
+    "//mojo/common/test:run_all_unittests",
+    "//mojo/environment:chromium",
+    "//mojo/public/cpp/bindings",
+    "//testing/gtest",
+    "//url",
+  ]
+}
+
+mojom("test_bindings") {
+  sources = [ "test.mojom" ]
+}
diff --git a/mojo/application_manager/application_loader.cc b/mojo/application_manager/application_loader.cc
new file mode 100644
index 0000000..60dec66
--- /dev/null
+++ b/mojo/application_manager/application_loader.cc
@@ -0,0 +1,30 @@
+// 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 "mojo/application_manager/application_loader.h"
+
+#include "base/logging.h"
+
+namespace mojo {
+
+ApplicationLoader::SimpleLoadCallbacks::SimpleLoadCallbacks(
+    ScopedMessagePipeHandle shell_handle)
+    : shell_handle_(shell_handle.Pass()) {
+}
+
+ApplicationLoader::SimpleLoadCallbacks::~SimpleLoadCallbacks() {
+}
+
+ScopedMessagePipeHandle
+ApplicationLoader::SimpleLoadCallbacks::RegisterApplication() {
+  return shell_handle_.Pass();
+}
+
+void ApplicationLoader::SimpleLoadCallbacks::LoadWithContentHandler(
+    const GURL& content_handle_url,
+    URLResponsePtr url_response) {
+  NOTREACHED();
+}
+
+}  // namespace mojo
diff --git a/mojo/application_manager/application_loader.h b/mojo/application_manager/application_loader.h
new file mode 100644
index 0000000..b7d9f19
--- /dev/null
+++ b/mojo/application_manager/application_loader.h
@@ -0,0 +1,88 @@
+// 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 MOJO_APPLICATION_MANAGER_APPLICATION_LOADER_H_
+#define MOJO_APPLICATION_MANAGER_APPLICATION_LOADER_H_
+
+#include "base/memory/ref_counted.h"
+#include "mojo/application_manager/application_manager_export.h"
+#include "mojo/public/cpp/system/core.h"
+#include "mojo/services/public/interfaces/network/url_loader.mojom.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:
+  class MOJO_APPLICATION_MANAGER_EXPORT LoadCallbacks
+      : public base::RefCounted<LoadCallbacks> {
+   public:
+    // Register the requested application with ApplicationManager. If the
+    // returned handle is valid, it should be used to implement the
+    // mojo::Application interface.
+    virtual ScopedMessagePipeHandle RegisterApplication() = 0;
+
+    // Load the requested application with a content handler.
+    virtual void LoadWithContentHandler(const GURL& content_handler_url,
+                                        URLResponsePtr url_response) = 0;
+
+   protected:
+    friend base::RefCounted<LoadCallbacks>;
+    virtual ~LoadCallbacks() {}
+  };
+
+  // Implements RegisterApplication() by returning a handle that was specified
+  // at construction time. LoadWithContentHandler() is not supported.
+  class MOJO_APPLICATION_MANAGER_EXPORT SimpleLoadCallbacks
+      : public LoadCallbacks {
+   public:
+    SimpleLoadCallbacks(ScopedMessagePipeHandle shell_handle);
+    virtual ScopedMessagePipeHandle RegisterApplication() override;
+    virtual void LoadWithContentHandler(const GURL& content_handler_url,
+                                        URLResponsePtr response) override;
+
+   private:
+    ScopedMessagePipeHandle shell_handle_;
+    virtual ~SimpleLoadCallbacks();
+  };
+
+  virtual ~ApplicationLoader() {}
+
+  // Load the application named |url|. Applications can be loaded two ways:
+  //
+  // 1. |url| can refer directly to a Mojo application. In this case, call
+  //    callbacks->RegisterApplication(). The returned handle should be used to
+  //    implement the mojo.Application interface. Note that the returned handle
+  //    can be invalid in the case where the application has already been
+  //    loaded.
+  //
+  // 2. |url| can refer to some content that can be handled by some other Mojo
+  //    application. In this case, call callbacks->LoadWithContentHandler() 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,
+                    scoped_refptr<LoadCallbacks> callbacks) = 0;
+
+  // Called when the Application exits.
+  virtual void OnApplicationError(ApplicationManager* manager,
+                                  const GURL& url) = 0;
+
+ protected:
+  ApplicationLoader() {}
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_APPLICATION_MANAGER_APPLICATION_LOADER_H_
diff --git a/mojo/application_manager/application_manager.cc b/mojo/application_manager/application_manager.cc
new file mode 100644
index 0000000..b183d9f
--- /dev/null
+++ b/mojo/application_manager/application_manager.cc
@@ -0,0 +1,328 @@
+// 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 "mojo/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/application_manager/application_loader.h"
+#include "mojo/common/common_type_converters.h"
+#include "mojo/public/cpp/application/connect.h"
+#include "mojo/public/interfaces/application/application.mojom.h"
+#include "mojo/public/interfaces/application/shell.mojom.h"
+#include "mojo/services/public/interfaces/content_handler/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:
+  virtual void ConnectToService(
+      const String& service_name,
+      ScopedMessagePipeHandle client_handle) override {}
+};
+
+}  // namespace
+
+ApplicationManager::Delegate::~Delegate() {}
+
+class ApplicationManager::LoadCallbacksImpl
+    : public ApplicationLoader::LoadCallbacks {
+ public:
+  LoadCallbacksImpl(base::WeakPtr<ApplicationManager> manager,
+                    const GURL& requested_url,
+                    const GURL& requestor_url,
+                    ServiceProviderPtr service_provider)
+      : manager_(manager),
+        requested_url_(requested_url),
+        requestor_url_(requestor_url),
+        service_provider_(service_provider.Pass()) {}
+
+ private:
+  virtual ~LoadCallbacksImpl() {}
+
+  // LoadCallbacks implementation
+  virtual ScopedMessagePipeHandle RegisterApplication() override {
+    ScopedMessagePipeHandle shell_handle;
+    if (manager_) {
+      manager_->RegisterLoadedApplication(requested_url_,
+                                          requestor_url_,
+                                          service_provider_.Pass(),
+                                          &shell_handle);
+    }
+    return shell_handle.Pass();
+  }
+
+  virtual void LoadWithContentHandler(const GURL& content_handler_url,
+                                      URLResponsePtr url_response) override {
+    if (manager_) {
+      manager_->LoadWithContentHandler(requested_url_,
+                                       requestor_url_,
+                                       content_handler_url,
+                                       url_response.Pass(),
+                                       service_provider_.Pass());
+    }
+  }
+
+  base::WeakPtr<ApplicationManager> manager_;
+  GURL requested_url_;
+  GURL requestor_url_;
+  ServiceProviderPtr service_provider_;
+};
+
+class ApplicationManager::ShellImpl : public InterfaceImpl<Shell> {
+ public:
+  ShellImpl(ApplicationManager* manager, const GURL& url)
+      : manager_(manager), url_(url) {}
+
+  virtual ~ShellImpl() {}
+
+  void ConnectToClient(const GURL& requestor_url,
+                       ServiceProviderPtr service_provider) {
+    client()->AcceptConnection(String::From(requestor_url),
+                               service_provider.Pass());
+  }
+
+  // ServiceProvider implementation:
+  virtual void ConnectToApplication(
+      const String& app_url,
+      InterfaceRequest<ServiceProvider> in_service_provider) override {
+    ServiceProviderPtr out_service_provider;
+    out_service_provider.Bind(in_service_provider.PassMessagePipe());
+    manager_->ConnectToApplication(
+        app_url.To<GURL>(), url_, out_service_provider.Pass());
+  }
+
+  const GURL& url() const { return url_; }
+
+ private:
+  virtual void OnConnectionError() override {
+    manager_->OnShellImplError(this);
+  }
+
+  ApplicationManager* const manager_;
+  const GURL url_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellImpl);
+};
+
+struct ApplicationManager::ContentHandlerConnection {
+  ContentHandlerConnection(ApplicationManager* manager,
+                           const GURL& content_handler_url) {
+    ServiceProviderPtr service_provider;
+    BindToProxy(&service_provider_impl, &service_provider);
+    manager->ConnectToApplication(
+        content_handler_url, GURL(), service_provider.Pass());
+    mojo::ConnectToService(service_provider_impl.client(), &content_handler);
+  }
+
+  StubServiceProvider service_provider_impl;
+  ContentHandlerPtr content_handler;
+};
+
+// 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_(NULL),
+      interceptor_(NULL),
+      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_);
+}
+
+// static
+ApplicationManager* ApplicationManager::GetInstance() {
+  static base::LazyInstance<ApplicationManager> instance =
+      LAZY_INSTANCE_INITIALIZER;
+  has_created_instance = true;
+  return &instance.Get();
+}
+
+void ApplicationManager::ConnectToApplication(
+    const GURL& url,
+    const GURL& requestor_url,
+    ServiceProviderPtr service_provider) {
+  URLToShellImplMap::const_iterator shell_it = url_to_shell_impl_.find(url);
+  if (shell_it != url_to_shell_impl_.end()) {
+    ConnectToClient(
+        shell_it->second, url, requestor_url, service_provider.Pass());
+    return;
+  }
+
+  scoped_refptr<LoadCallbacksImpl> callbacks(
+      new LoadCallbacksImpl(weak_ptr_factory_.GetWeakPtr(),
+                            url,
+                            requestor_url,
+                            service_provider.Pass()));
+  GetLoaderForURL(url)->Load(this, url, callbacks);
+}
+
+void ApplicationManager::ConnectToClient(ShellImpl* shell_impl,
+                                         const GURL& url,
+                                         const GURL& requestor_url,
+                                         ServiceProviderPtr service_provider) {
+  if (interceptor_) {
+    shell_impl->ConnectToClient(
+        requestor_url,
+        interceptor_->OnConnectToClient(url, service_provider.Pass()));
+  } else {
+    shell_impl->ConnectToClient(requestor_url, service_provider.Pass());
+  }
+}
+
+void ApplicationManager::RegisterExternalApplication(
+    const GURL& url,
+    ScopedMessagePipeHandle shell_handle) {
+  url_to_shell_impl_[url] =
+      WeakBindToPipe(new ShellImpl(this, url), shell_handle.Pass());
+}
+
+void ApplicationManager::RegisterLoadedApplication(
+    const GURL& url,
+    const GURL& requestor_url,
+    ServiceProviderPtr service_provider,
+    ScopedMessagePipeHandle* shell_handle) {
+  ShellImpl* shell_impl = NULL;
+  URLToShellImplMap::iterator iter = url_to_shell_impl_.find(url);
+  if (iter != url_to_shell_impl_.end()) {
+    // This can happen because services are loaded asynchronously. So if we get
+    // two requests for the same service close to each other, we might get here
+    // and find that we already have it.
+    shell_impl = iter->second;
+  } else {
+    MessagePipe pipe;
+    URLToArgsMap::const_iterator args_it = url_to_args_.find(url);
+    Array<String> args;
+    if (args_it != url_to_args_.end())
+      args = Array<String>::From(args_it->second);
+    shell_impl = WeakBindToPipe(new ShellImpl(this, url), pipe.handle1.Pass());
+    url_to_shell_impl_[url] = shell_impl;
+    *shell_handle = pipe.handle0.Pass();
+    shell_impl->client()->Initialize(args.Pass());
+  }
+
+  ConnectToClient(shell_impl, url, requestor_url, service_provider.Pass());
+}
+
+void ApplicationManager::LoadWithContentHandler(
+    const GURL& content_url,
+    const GURL& requestor_url,
+    const GURL& content_handler_url,
+    URLResponsePtr url_response,
+    ServiceProviderPtr service_provider) {
+  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;
+  }
+
+  InterfaceRequest<ServiceProvider> spir;
+  spir.Bind(service_provider.PassMessagePipe());
+  connection->content_handler->OnConnect(
+      content_url.spec(), url_response.Pass(), spir.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;
+}
+
+void ApplicationManager::SetInterceptor(Interceptor* interceptor) {
+  interceptor_ = interceptor;
+}
+
+ApplicationLoader* ApplicationManager::GetLoaderForURL(const GURL& url) {
+  URLToLoaderMap::const_iterator url_it = url_to_loader_.find(url);
+  if (url_it != url_to_loader_.end())
+    return url_it->second;
+  SchemeToLoaderMap::const_iterator scheme_it =
+      scheme_to_loader_.find(url.scheme());
+  if (scheme_it != scheme_to_loader_.end())
+    return scheme_it->second;
+  return default_loader_.get();
+}
+
+void ApplicationManager::OnShellImplError(ShellImpl* shell_impl) {
+  // Called from ~ShellImpl, so we do not need to call Destroy here.
+  const GURL url = shell_impl->url();
+  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(url);
+  if (loader)
+    loader->OnApplicationError(this, url);
+  if (delegate_)
+    delegate_->OnApplicationError(url);
+}
+
+ScopedMessagePipeHandle ApplicationManager::ConnectToServiceByName(
+    const GURL& application_url,
+    const std::string& interface_name) {
+  StubServiceProvider* stub_sp = new StubServiceProvider;
+  ServiceProviderPtr spp;
+  BindToProxy(stub_sp, &spp);
+  ConnectToApplication(application_url, GURL(), spp.Pass());
+  MessagePipe pipe;
+  stub_sp->GetRemoteServiceProvider()->ConnectToService(interface_name,
+                                                        pipe.handle1.Pass());
+  return pipe.handle0.Pass();
+}
+}  // namespace mojo
diff --git a/mojo/application_manager/application_manager.h b/mojo/application_manager/application_manager.h
new file mode 100644
index 0000000..af74d8b
--- /dev/null
+++ b/mojo/application_manager/application_manager.h
@@ -0,0 +1,163 @@
+// 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 MOJO_APPLICATION_MANAGER_APPLICATION_MANAGER_H_
+#define MOJO_APPLICATION_MANAGER_APPLICATION_MANAGER_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/application_manager/application_loader.h"
+#include "mojo/application_manager/application_manager_export.h"
+#include "mojo/public/interfaces/application/service_provider.mojom.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) = 0;
+  };
+
+  // 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);
+  };
+
+  // Interface class for debugging only.
+  class Interceptor {
+   public:
+    virtual ~Interceptor() {}
+    // Called when ApplicationManager::Connect is called.
+    virtual ServiceProviderPtr OnConnectToClient(
+        const GURL& url,
+        ServiceProviderPtr service_provider) = 0;
+  };
+
+  ApplicationManager();
+  ~ApplicationManager();
+
+  // Returns a shared instance, creating it if necessary.
+  static ApplicationManager* GetInstance();
+
+  void SetDelegate(Delegate* delegate) { delegate_ = delegate; }
+
+  // Loads a service if necessary and establishes a new client connection.
+  void ConnectToApplication(const GURL& application_url,
+                            const GURL& requestor_url,
+                            ServiceProviderPtr service_provider);
+
+  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);
+
+  void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+
+  // 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);
+
+  // Allows to interpose a debugger to service connections.
+  void SetInterceptor(Interceptor* interceptor);
+
+  // 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();
+
+ private:
+  struct ContentHandlerConnection;
+  class LoadCallbacksImpl;
+  class ShellImpl;
+
+  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 ConnectToClient(ShellImpl* shell_impl,
+                       const GURL& url,
+                       const GURL& requestor_url,
+                       ServiceProviderPtr service_provider);
+
+  void RegisterLoadedApplication(const GURL& service_url,
+                                 const GURL& requestor_url,
+                                 ServiceProviderPtr service_provider,
+                                 ScopedMessagePipeHandle* shell_handle);
+
+  void LoadWithContentHandler(const GURL& content_url,
+                              const GURL& requestor_url,
+                              const GURL& content_handler_url,
+                              URLResponsePtr url_response,
+                              ServiceProviderPtr service_provider);
+
+  // Returns the Loader to use for a url (using default if not overridden.)
+  // The preference is to use a loader that's been specified for an url first,
+  // then one that's been specified for a scheme, then the default.
+  ApplicationLoader* GetLoaderForURL(const GURL& url);
+
+  // Removes a ShellImpl when it encounters an error.
+  void OnShellImplError(ShellImpl* shell_impl);
+
+  Delegate* delegate_;
+  // Loader management.
+  URLToLoaderMap url_to_loader_;
+  SchemeToLoaderMap scheme_to_loader_;
+  scoped_ptr<ApplicationLoader> default_loader_;
+  Interceptor* interceptor_;
+
+  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  // MOJO_APPLICATION_MANAGER_APPLICATION_MANAGER_H_
diff --git a/mojo/application_manager/application_manager_export.h b/mojo/application_manager/application_manager_export.h
new file mode 100644
index 0000000..9af43cf
--- /dev/null
+++ b/mojo/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 MOJO_APPLICATION_MANAGER_APPLICATION_MANAGER_EXPORT_H_
+#define MOJO_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  // MOJO_APPLICATION_MANAGER_APPLICATION_MANAGER_EXPORT_H_
diff --git a/mojo/application_manager/application_manager_unittest.cc b/mojo/application_manager/application_manager_unittest.cc
new file mode 100644
index 0000000..5763265
--- /dev/null
+++ b/mojo/application_manager/application_manager_unittest.cc
@@ -0,0 +1,686 @@
+// 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/message_loop/message_loop.h"
+#include "mojo/application_manager/application_loader.h"
+#include "mojo/application_manager/application_manager.h"
+#include "mojo/application_manager/background_shell_application_loader.h"
+#include "mojo/application_manager/test.mojom.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 "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() {}
+  virtual ~QuitMessageLoopErrorHandler() {}
+
+  // |ErrorHandler| implementation:
+  virtual 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;
+  }
+
+  virtual ~TestServiceImpl() { --context_->num_impls; }
+
+  virtual void OnConnectionError() override {
+    if (!base::MessageLoop::current()->is_running())
+      return;
+    base::MessageLoop::current()->Quit();
+  }
+
+  // TestService implementation:
+  virtual 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);
+  }
+
+  virtual ~TestClientImpl() { service_.reset(); }
+
+  virtual void AckTest() override {
+    if (quit_after_ack_)
+      base::MessageLoop::current()->Quit();
+  }
+
+  void Test(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) {}
+
+  virtual ~TestApplicationLoader() {
+    if (context_)
+      ++context_->num_loader_deletes;
+    test_app_.reset(NULL);
+  }
+
+  void set_context(TestContext* context) { context_ = context; }
+  int num_loads() const { return num_loads_; }
+  std::vector<std::string> GetArgs() {
+    return test_app_->args().To<std::vector<std::string> >();
+  }
+
+ private:
+  // ApplicationLoader implementation.
+  virtual void Load(ApplicationManager* manager,
+                    const GURL& url,
+                    scoped_refptr<LoadCallbacks> callbacks) override {
+    ++num_loads_;
+    test_app_.reset(
+        new ApplicationImpl(this, callbacks->RegisterApplication().Pass()));
+  }
+
+  virtual void OnApplicationError(ApplicationManager* manager,
+                                  const GURL& url) override {}
+
+  // ApplicationDelegate implementation.
+  virtual bool ConfigureIncomingConnection(
+      ApplicationConnection* connection) override {
+    connection->AddService(this);
+    return true;
+  }
+
+  // InterfaceFactory implementation.
+  virtual 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 InterfaceImpl<TestA> {
+ public:
+  TestAImpl(ApplicationConnection* connection, TesterContext* test_context)
+      : test_context_(test_context) {
+    connection->ConnectToApplication(kTestBURLString)->ConnectToService(&b_);
+  }
+  virtual ~TestAImpl() {
+    test_context_->IncrementNumADeletes();
+    if (base::MessageLoop::current()->is_running())
+      Quit();
+  }
+
+ private:
+  virtual void CallB() override {
+    b_->B(base::Bind(&TestAImpl::Quit, base::Unretained(this)));
+  }
+
+  virtual 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_;
+};
+
+class TestBImpl : public InterfaceImpl<TestB> {
+ public:
+  TestBImpl(ApplicationConnection* connection, TesterContext* test_context)
+      : test_context_(test_context) {
+    connection->ConnectToService(&c_);
+  }
+
+  virtual ~TestBImpl() {
+    test_context_->IncrementNumBDeletes();
+    if (base::MessageLoop::current()->is_running())
+      base::MessageLoop::current()->Quit();
+    test_context_->QuitSoon();
+  }
+
+ private:
+  virtual void B(const mojo::Callback<void()>& callback) override {
+    test_context_->IncrementNumBCalls();
+    callback.Run();
+  }
+
+  virtual 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) {}
+
+  virtual ~TestCImpl() { test_context_->IncrementNumCDeletes(); }
+
+ private:
+  virtual 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) {}
+  virtual ~Tester() {}
+
+ private:
+  virtual void Load(ApplicationManager* manager,
+                    const GURL& url,
+                    scoped_refptr<LoadCallbacks> callbacks) override {
+    app_.reset(
+        new ApplicationImpl(this, callbacks->RegisterApplication().Pass()));
+  }
+
+  virtual void OnApplicationError(ApplicationManager* manager,
+                                  const GURL& url) override {}
+
+  virtual 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;
+  }
+
+  virtual bool ConfigureOutgoingConnection(
+      ApplicationConnection* connection) override {
+    // If we're connecting to B, then add C.
+    if (connection->GetRemoteApplicationURL() == kTestBURLString)
+      connection->AddService<TestC>(this);
+    return true;
+  }
+
+  virtual void Create(ApplicationConnection* connection,
+                      InterfaceRequest<TestA> request) override {
+    BindToRequest(new TestAImpl(connection, context_), &request);
+  }
+
+  virtual void Create(ApplicationConnection* connection,
+                      InterfaceRequest<TestB> request) override {
+    BindToRequest(new TestBImpl(connection, context_), &request);
+  }
+
+  virtual void Create(ApplicationConnection* connection,
+                      InterfaceRequest<TestC> request) override {
+    BindToRequest(new TestCImpl(connection, context_), &request);
+  }
+
+  TesterContext* context_;
+  scoped_ptr<ApplicationImpl> app_;
+  std::string requestor_url_;
+};
+
+class TestServiceInterceptor : public ApplicationManager::Interceptor {
+ public:
+  TestServiceInterceptor() : call_count_(0) {}
+
+  virtual ServiceProviderPtr OnConnectToClient(
+      const GURL& url,
+      ServiceProviderPtr service_provider) override {
+    ++call_count_;
+    url_ = url;
+    return service_provider.Pass();
+  }
+
+  std::string url_spec() const {
+    if (!url_.is_valid())
+      return "invalid url";
+    return url_.spec();
+  }
+
+  int call_count() const { return call_count_; }
+
+ private:
+  int call_count_;
+  GURL url_;
+  DISALLOW_COPY_AND_ASSIGN(TestServiceInterceptor);
+};
+
+}  // namespace
+
+class ApplicationManagerTest : public testing::Test {
+ public:
+  ApplicationManagerTest() : tester_context_(&loop_) {}
+
+  virtual ~ApplicationManagerTest() {}
+
+  virtual void SetUp() override {
+    application_manager_.reset(new ApplicationManager);
+    TestApplicationLoader* default_loader = new TestApplicationLoader;
+    default_loader->set_context(&context_);
+    application_manager_->set_default_loader(
+        scoped_ptr<ApplicationLoader>(default_loader));
+
+    TestServicePtr service_proxy;
+    application_manager_->ConnectToService(GURL(kTestURLString),
+                                           &service_proxy);
+    test_client_.reset(new TestClientImpl(service_proxy.Pass()));
+  }
+
+  virtual void TearDown() override {
+    test_client_.reset(NULL);
+    application_manager_.reset(NULL);
+  }
+
+  scoped_ptr<BackgroundShellApplicationLoader> MakeLoader(
+      const std::string& requestor_url) {
+    scoped_ptr<ApplicationLoader> real_loader(
+        new Tester(&tester_context_, requestor_url));
+    scoped_ptr<BackgroundShellApplicationLoader> loader(
+        new BackgroundShellApplicationLoader(real_loader.Pass(),
+                                             std::string(),
+                                             base::MessageLoop::TYPE_DEFAULT));
+    return loader.Pass();
+  }
+
+  void AddLoaderForURL(const GURL& url, const std::string& requestor_url) {
+    application_manager_->SetLoaderForURL(
+        MakeLoader(requestor_url).PassAs<ApplicationLoader>(), url);
+  }
+
+  bool HasFactoryForTestURL() {
+    ApplicationManager::TestAPI manager_test_api(application_manager_.get());
+    return manager_test_api.HasFactoryForURL(GURL(kTestURLString));
+  }
+
+ protected:
+  base::ShadowingAtExitManager at_exit_;
+  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;
+  GURL test_url("test:test");
+  TestContext context;
+  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;
+  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);
+  TestContext context;
+  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;
+    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, Interceptor) {
+  TestServiceInterceptor interceptor;
+  TestApplicationLoader* default_loader = new TestApplicationLoader;
+  application_manager_->set_default_loader(
+      scoped_ptr<ApplicationLoader>(default_loader));
+  application_manager_->SetInterceptor(&interceptor);
+
+  std::string url("test:test3");
+  TestServicePtr test_service;
+  application_manager_->ConnectToService(GURL(url), &test_service);
+
+  EXPECT_EQ(1, interceptor.call_count());
+  EXPECT_EQ(url, interceptor.url_spec());
+  EXPECT_EQ(1, default_loader->num_loads());
+}
+
+}  // namespace mojo
diff --git a/mojo/application_manager/background_shell_application_loader.cc b/mojo/application_manager/background_shell_application_loader.cc
new file mode 100644
index 0000000..e6664db
--- /dev/null
+++ b/mojo/application_manager/background_shell_application_loader.cc
@@ -0,0 +1,127 @@
+// 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 "mojo/application_manager/background_shell_application_loader.h"
+
+#include "base/bind.h"
+#include "base/run_loop.h"
+#include "mojo/application_manager/application_manager.h"
+
+namespace mojo {
+
+class BackgroundShellApplicationLoader::BackgroundLoader {
+ public:
+  explicit BackgroundLoader(ApplicationLoader* loader) : loader_(loader) {}
+  ~BackgroundLoader() {}
+
+  void Load(ApplicationManager* manager,
+            const GURL& url,
+            ScopedMessagePipeHandle shell_handle) {
+    scoped_refptr<LoadCallbacks> callbacks(
+        new ApplicationLoader::SimpleLoadCallbacks(shell_handle.Pass()));
+    loader_->Load(manager, url, callbacks);
+  }
+
+  void OnApplicationError(ApplicationManager* manager, const GURL& url) {
+    loader_->OnApplicationError(manager, url);
+  }
+
+ private:
+  ApplicationLoader* loader_;  // Owned by BackgroundShellApplicationLoader
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundLoader);
+};
+
+BackgroundShellApplicationLoader::BackgroundShellApplicationLoader(
+    scoped_ptr<ApplicationLoader> real_loader,
+    const std::string& thread_name,
+    base::MessageLoop::Type message_loop_type)
+    : loader_(real_loader.Pass()),
+      message_loop_type_(message_loop_type),
+      thread_name_(thread_name),
+      message_loop_created_(true, false),
+      background_loader_(NULL) {
+}
+
+BackgroundShellApplicationLoader::~BackgroundShellApplicationLoader() {
+  if (thread_)
+    thread_->Join();
+}
+
+void BackgroundShellApplicationLoader::Load(
+    ApplicationManager* manager,
+    const GURL& url,
+    scoped_refptr<LoadCallbacks> callbacks) {
+  ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
+  if (!shell_handle.is_valid())
+    return;
+
+  if (!thread_) {
+    // TODO(tim): It'd be nice if we could just have each Load call
+    // result in a new thread like DynamicService{Loader, Runner}. But some
+    // loaders are creating multiple ApplicationImpls (NetworkApplicationLoader)
+    // sharing a delegate (etc). So we have to keep it single threaded, wait
+    // for the thread to initialize, and post to the TaskRunner for subsequent
+    // Load calls for now.
+    thread_.reset(new base::DelegateSimpleThread(this, thread_name_));
+    thread_->Start();
+    message_loop_created_.Wait();
+    DCHECK(task_runner_.get());
+  }
+
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(
+          &BackgroundShellApplicationLoader::LoadOnBackgroundThread,
+          base::Unretained(this),
+          manager,
+          url,
+          base::Owned(new ScopedMessagePipeHandle(shell_handle.Pass()))));
+}
+
+void BackgroundShellApplicationLoader::OnApplicationError(
+    ApplicationManager* manager,
+    const GURL& url) {
+  task_runner_->PostTask(FROM_HERE,
+                         base::Bind(&BackgroundShellApplicationLoader::
+                                        OnApplicationErrorOnBackgroundThread,
+                                    base::Unretained(this),
+                                    manager,
+                                    url));
+}
+
+void BackgroundShellApplicationLoader::Run() {
+  base::MessageLoop message_loop(message_loop_type_);
+  base::RunLoop loop;
+  task_runner_ = message_loop.task_runner();
+  quit_closure_ = loop.QuitClosure();
+  message_loop_created_.Signal();
+  loop.Run();
+
+  delete background_loader_;
+  background_loader_ = NULL;
+  // Destroy |loader_| on the thread it's actually used on.
+  loader_.reset();
+}
+
+void BackgroundShellApplicationLoader::LoadOnBackgroundThread(
+    ApplicationManager* manager,
+    const GURL& url,
+    ScopedMessagePipeHandle* shell_handle) {
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  if (!background_loader_)
+    background_loader_ = new BackgroundLoader(loader_.get());
+  background_loader_->Load(manager, url, shell_handle->Pass());
+}
+
+void BackgroundShellApplicationLoader::OnApplicationErrorOnBackgroundThread(
+    ApplicationManager* manager,
+    const GURL& url) {
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  if (!background_loader_)
+    background_loader_ = new BackgroundLoader(loader_.get());
+  background_loader_->OnApplicationError(manager, url);
+}
+
+}  // namespace mojo
diff --git a/mojo/application_manager/background_shell_application_loader.h b/mojo/application_manager/background_shell_application_loader.h
new file mode 100644
index 0000000..3c56290
--- /dev/null
+++ b/mojo/application_manager/background_shell_application_loader.h
@@ -0,0 +1,77 @@
+// 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 MOJO_APPLICATION_MANAGER_BACKGROUND_SHELL_APPLICATION_LOADER_H_
+#define MOJO_APPLICATION_MANAGER_BACKGROUND_SHELL_APPLICATION_LOADER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#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"
+
+namespace mojo {
+
+// TODO(tim): Eventually this should be Android-only to support services
+// that we need to bundle with the shell (such as NetworkService). Perhaps
+// we should move it to shell/ as well.
+class MOJO_APPLICATION_MANAGER_EXPORT BackgroundShellApplicationLoader
+    : public ApplicationLoader,
+      public base::DelegateSimpleThread::Delegate {
+ public:
+  BackgroundShellApplicationLoader(scoped_ptr<ApplicationLoader> real_loader,
+                                   const std::string& thread_name,
+                                   base::MessageLoop::Type message_loop_type);
+  virtual ~BackgroundShellApplicationLoader();
+
+  // ApplicationLoader overrides:
+  virtual void Load(ApplicationManager* manager,
+                    const GURL& url,
+                    scoped_refptr<LoadCallbacks> callbacks) override;
+  virtual void OnApplicationError(ApplicationManager* manager,
+                                  const GURL& url) override;
+
+ private:
+  class BackgroundLoader;
+
+  // |base::DelegateSimpleThread::Delegate| method:
+  virtual void Run() override;
+
+  // These functions are exected on the background thread. They call through
+  // to |background_loader_| to do the actual loading.
+  // TODO: having this code take a |manager| is fragile (as ApplicationManager
+  // isn't thread safe).
+  void LoadOnBackgroundThread(ApplicationManager* manager,
+                              const GURL& url,
+                              ScopedMessagePipeHandle* shell_handle);
+  void OnApplicationErrorOnBackgroundThread(ApplicationManager* manager,
+                                            const GURL& url);
+  bool quit_on_shutdown_;
+  scoped_ptr<ApplicationLoader> loader_;
+
+  const base::MessageLoop::Type message_loop_type_;
+  const std::string thread_name_;
+
+  // Created on |thread_| during construction of |this|. Protected against
+  // uninitialized use by |message_loop_created_|, and protected against
+  // use-after-free by holding a reference to the thread-safe object. Note
+  // that holding a reference won't hold |thread_| from exiting.
+  scoped_refptr<base::TaskRunner> task_runner_;
+  base::WaitableEvent message_loop_created_;
+
+  // Lives on |thread_|.
+  base::Closure quit_closure_;
+
+  scoped_ptr<base::DelegateSimpleThread> thread_;
+
+  // Lives on |thread_|. Trivial interface that calls through to |loader_|.
+  BackgroundLoader* background_loader_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundShellApplicationLoader);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_APPLICATION_MANAGER_BACKGROUND_SHELL_APPLICATION_LOADER_H_
diff --git a/mojo/application_manager/background_shell_application_loader_unittest.cc b/mojo/application_manager/background_shell_application_loader_unittest.cc
new file mode 100644
index 0000000..acf1a01
--- /dev/null
+++ b/mojo/application_manager/background_shell_application_loader_unittest.cc
@@ -0,0 +1,56 @@
+// 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 "mojo/application_manager/background_shell_application_loader.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+
+namespace {
+
+class DummyLoader : public ApplicationLoader {
+ public:
+  DummyLoader() : simulate_app_quit_(true) {}
+  virtual ~DummyLoader() {}
+
+  // ApplicationLoader overrides:
+  virtual void Load(ApplicationManager* manager,
+                    const GURL& url,
+                    scoped_refptr<LoadCallbacks> callbacks) override {
+    if (simulate_app_quit_)
+      base::MessageLoop::current()->Quit();
+  }
+
+  virtual void OnApplicationError(ApplicationManager* manager,
+                                  const GURL& url) override {}
+
+  void DontSimulateAppQuit() { simulate_app_quit_ = false; }
+
+ private:
+  bool simulate_app_quit_;
+};
+
+}  // namespace
+
+// Tests that the loader can start and stop gracefully.
+TEST(BackgroundShellApplicationLoaderTest, StartStop) {
+  scoped_ptr<ApplicationLoader> real_loader(new DummyLoader());
+  BackgroundShellApplicationLoader loader(
+      real_loader.Pass(), "test", base::MessageLoop::TYPE_DEFAULT);
+}
+
+// Tests that the loader can load a service that is well behaved (quits
+// itself).
+TEST(BackgroundShellApplicationLoaderTest, Load) {
+  scoped_ptr<ApplicationLoader> real_loader(new DummyLoader());
+  BackgroundShellApplicationLoader loader(
+      real_loader.Pass(), "test", base::MessageLoop::TYPE_DEFAULT);
+  MessagePipe dummy;
+  scoped_refptr<ApplicationLoader::SimpleLoadCallbacks> callbacks(
+      new ApplicationLoader::SimpleLoadCallbacks(dummy.handle0.Pass()));
+  loader.Load(NULL, GURL(), callbacks);
+}
+
+}  // namespace mojo
diff --git a/mojo/application_manager/test.mojom b/mojo/application_manager/test.mojom
new file mode 100644
index 0000000..6a03581
--- /dev/null
+++ b/mojo/application_manager/test.mojom
@@ -0,0 +1,30 @@
+// 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() => ();
+};
+
+}