summaryrefslogtreecommitdiffstats
path: root/mojo/shell/public
diff options
context:
space:
mode:
authorben <ben@chromium.org>2016-01-11 18:44:08 -0800
committerCommit bot <commit-bot@chromium.org>2016-01-12 02:44:59 +0000
commit273c1e30241a8a5509ad9b307380ed8600ba82d8 (patch)
tree25da3f1a02f1f9d5f129ba8d794d20b51355a07b /mojo/shell/public
parent9c1122c7163411be938195ba546460ba54d33b00 (diff)
downloadchromium_src-273c1e30241a8a5509ad9b307380ed8600ba82d8.zip
chromium_src-273c1e30241a8a5509ad9b307380ed8600ba82d8.tar.gz
chromium_src-273c1e30241a8a5509ad9b307380ed8600ba82d8.tar.bz2
Move mojo/application/public -> mojo/shell/public
TBR=sky@chromium.org http://crbug.com/575308 Review URL: https://codereview.chromium.org/1565343003 Cr-Commit-Position: refs/heads/master@{#368776}
Diffstat (limited to 'mojo/shell/public')
-rw-r--r--mojo/shell/public/cpp/BUILD.gn111
-rw-r--r--mojo/shell/public/cpp/app_lifetime_helper.h81
-rw-r--r--mojo/shell/public/cpp/application_connection.h144
-rw-r--r--mojo/shell/public/cpp/application_delegate.h54
-rw-r--r--mojo/shell/public/cpp/application_impl.h186
-rw-r--r--mojo/shell/public/cpp/application_runner.h63
-rw-r--r--mojo/shell/public/cpp/application_test_base.h59
-rw-r--r--mojo/shell/public/cpp/connect.h25
-rw-r--r--mojo/shell/public/cpp/content_handler_factory.h81
-rw-r--r--mojo/shell/public/cpp/initialize_base_and_icu.cc50
-rw-r--r--mojo/shell/public/cpp/interface_factory.h30
-rw-r--r--mojo/shell/public/cpp/interface_factory_impl.h49
-rw-r--r--mojo/shell/public/cpp/lazy_interface_ptr.h46
-rw-r--r--mojo/shell/public/cpp/lib/app_lifetime_helper.cc94
-rw-r--r--mojo/shell/public/cpp/lib/application_delegate.cc34
-rw-r--r--mojo/shell/public/cpp/lib/application_impl.cc181
-rw-r--r--mojo/shell/public/cpp/lib/application_runner.cc77
-rw-r--r--mojo/shell/public/cpp/lib/application_test_base.cc158
-rw-r--r--mojo/shell/public/cpp/lib/application_test_main.cc23
-rw-r--r--mojo/shell/public/cpp/lib/content_handler_factory.cc143
-rw-r--r--mojo/shell/public/cpp/lib/init_commandline.cc22
-rw-r--r--mojo/shell/public/cpp/lib/interface_factory_connector.h39
-rw-r--r--mojo/shell/public/cpp/lib/service_connector_registry.cc61
-rw-r--r--mojo/shell/public/cpp/lib/service_connector_registry.h62
-rw-r--r--mojo/shell/public/cpp/lib/service_provider_impl.cc43
-rw-r--r--mojo/shell/public/cpp/lib/service_registry.cc138
-rw-r--r--mojo/shell/public/cpp/lib/service_registry.h83
-rw-r--r--mojo/shell/public/cpp/service_connector.h30
-rw-r--r--mojo/shell/public/cpp/service_provider_impl.h50
-rw-r--r--mojo/shell/public/cpp/tests/BUILD.gn18
-rw-r--r--mojo/shell/public/cpp/tests/service_registry_unittest.cc72
-rw-r--r--mojo/shell/public/interfaces/BUILD.gn22
-rw-r--r--mojo/shell/public/interfaces/application.mojom70
-rw-r--r--mojo/shell/public/interfaces/application_manager.mojom67
-rw-r--r--mojo/shell/public/interfaces/content_handler.mojom20
-rw-r--r--mojo/shell/public/interfaces/service_provider.mojom17
-rw-r--r--mojo/shell/public/interfaces/shell.mojom79
-rw-r--r--mojo/shell/public/java/BUILD.gn21
-rw-r--r--mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationConnection.java107
-rw-r--r--mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationDelegate.java37
-rw-r--r--mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationImpl.java71
-rw-r--r--mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationRunner.java32
-rw-r--r--mojo/shell/public/java/src/org/chromium/mojo/application/ServiceFactoryBinder.java30
-rw-r--r--mojo/shell/public/java/src/org/chromium/mojo/application/ShellHelper.java40
44 files changed, 2920 insertions, 0 deletions
diff --git a/mojo/shell/public/cpp/BUILD.gn b/mojo/shell/public/cpp/BUILD.gn
new file mode 100644
index 0000000..55cd782
--- /dev/null
+++ b/mojo/shell/public/cpp/BUILD.gn
@@ -0,0 +1,111 @@
+# 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.
+
+# GYP version: mojo/mojo_base.gyp:mojo_application_base
+source_set("cpp") {
+ public_deps = [
+ ":init_commandline",
+ ":sources",
+ ]
+}
+
+# Like the target above, but without special commandline initialization that
+# apps use.
+source_set("cpp_for_chromium") {
+ public_deps = [
+ ":sources",
+ ]
+}
+
+source_set("sources") {
+ sources = [
+ "app_lifetime_helper.h",
+ "application_connection.h",
+ "application_delegate.h",
+ "application_impl.h",
+ "application_runner.h",
+ "connect.h",
+ "initialize_base_and_icu.cc",
+ "interface_factory.h",
+ "interface_factory_impl.h",
+ "lib/app_lifetime_helper.cc",
+ "lib/application_delegate.cc",
+ "lib/application_impl.cc",
+ "lib/application_runner.cc",
+ "lib/interface_factory_connector.h",
+ "lib/service_connector_registry.cc",
+ "lib/service_connector_registry.h",
+ "lib/service_provider_impl.cc",
+ "lib/service_registry.cc",
+ "lib/service_registry.h",
+ "service_connector.h",
+ "service_provider_impl.h",
+ ]
+
+ deps = [
+ "//base:i18n",
+ "//mojo/common",
+ "//mojo/converters/network",
+ "//mojo/environment:chromium",
+ "//mojo/message_pump",
+ ]
+
+ public_deps = [
+ "//base",
+ "//mojo/public/cpp/bindings",
+ "//mojo/public/cpp/system",
+ "//mojo/shell/public/interfaces",
+ ]
+}
+
+source_set("init_commandline") {
+ sources = [
+ "lib/init_commandline.cc",
+ ]
+}
+
+source_set("content_handler") {
+ sources = [
+ "content_handler_factory.h",
+ "lib/content_handler_factory.cc",
+ ]
+ deps = [
+ ":cpp",
+
+ # TODO: this code should not depend on base.
+ "//base",
+ "//mojo/message_pump",
+ "//mojo/services/network/public/interfaces",
+ "//mojo/shell/public/interfaces:interfaces_cpp_sources",
+ ]
+}
+
+source_set("test_support") {
+ testonly = true
+ sources = [
+ "application_test_base.h",
+ "lib/application_test_base.cc",
+ "lib/application_test_main.cc",
+ ]
+
+ public_deps = [
+ ":cpp",
+ "//testing/gtest",
+ ]
+
+ deps = [
+ "//base",
+ "//base/test:test_support",
+ "//mojo/logging",
+ "//mojo/public/cpp/bindings",
+ "//mojo/public/cpp/environment",
+ "//mojo/public/cpp/system",
+ "//mojo/shell/public/interfaces:interfaces_cpp_sources",
+ ]
+
+ data_deps = []
+ if (is_android) {
+ data_deps += [ "//mojo/android" ]
+ }
+}
diff --git a/mojo/shell/public/cpp/app_lifetime_helper.h b/mojo/shell/public/cpp/app_lifetime_helper.h
new file mode 100644
index 0000000..ae2503f
--- /dev/null
+++ b/mojo/shell/public/cpp/app_lifetime_helper.h
@@ -0,0 +1,81 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_SHELL_PUBLIC_CPP_APP_LIFETIME_HELPER_H_
+#define MOJO_SHELL_PUBLIC_CPP_APP_LIFETIME_HELPER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+
+namespace mojo {
+
+class ApplicationImpl;
+class AppLifetimeHelper;
+
+// A service implementation should keep this object as a member variable to hold
+// a reference on the application.
+// Since services can live on different threads than the app, this class is
+// safe to use on any thread. However, each instance should only be used on one
+// thread at a time (otherwise there'll be races between the addref resulting
+// from cloning and destruction).
+class AppRefCount {
+ public:
+ ~AppRefCount();
+
+ // When a service creates another object that is held by the client, it should
+ // also vend to it a refcount using this method. That way if the caller stops
+ // holding on to the service but keeps the reference to the object, the app is
+ // still alive.
+ scoped_ptr<AppRefCount> Clone();
+
+ private:
+ friend AppLifetimeHelper;
+
+ AppRefCount(AppLifetimeHelper* app_lifetime_helper,
+ scoped_refptr<base::SingleThreadTaskRunner> app_task_runner);
+
+ // Don't need to use weak ptr because if the app thread is alive that means
+ // app is.
+ AppLifetimeHelper* app_lifetime_helper_;
+ scoped_refptr<base::SingleThreadTaskRunner> app_task_runner_;
+
+#ifndef NDEBUG
+ scoped_refptr<base::SingleThreadTaskRunner> clone_task_runner_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(AppRefCount);
+};
+
+// This is a helper class for apps to manage their lifetime, specifically so
+// apps can quit when they're not used anymore.
+// An app can contain an object of this class as a member variable. Each time it
+// creates an instance of a service, it gives it a refcount using
+// CreateAppRefCount. The service implementation then keeps that object as a
+// member variable. When all the service implemenations go away, the app will be
+// quit with a call to mojo::ApplicationImpl::Terminate().
+class AppLifetimeHelper {
+ public:
+ explicit AppLifetimeHelper(ApplicationImpl* app);
+ ~AppLifetimeHelper();
+
+ scoped_ptr<AppRefCount> CreateAppRefCount();
+
+ private:
+ friend AppRefCount;
+ void AddRef();
+ void Release();
+
+ friend ApplicationImpl;
+ void OnQuit();
+
+ ApplicationImpl* app_;
+ int ref_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppLifetimeHelper);
+};
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_APP_LIFETIME_HELPER_H_
diff --git a/mojo/shell/public/cpp/application_connection.h b/mojo/shell/public/cpp/application_connection.h
new file mode 100644
index 0000000..64d613d
--- /dev/null
+++ b/mojo/shell/public/cpp/application_connection.h
@@ -0,0 +1,144 @@
+// 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_SHELL_PUBLIC_CPP_APPLICATION_CONNECTION_H_
+#define MOJO_SHELL_PUBLIC_CPP_APPLICATION_CONNECTION_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+
+#include "base/memory/weak_ptr.h"
+#include "mojo/shell/public/cpp/lib/interface_factory_connector.h"
+#include "mojo/shell/public/interfaces/service_provider.mojom.h"
+
+namespace mojo {
+
+class ServiceConnector;
+
+// Represents a connection to another application. An instance of this class is
+// passed to ApplicationDelegate's ConfigureIncomingConnection() method each
+// time a connection is made to this app, and to ApplicationDelegate's
+// ConfigureOutgoingConnection() method when the app connects to another.
+//
+// To use, define a class that implements your specific service API (e.g.,
+// FooImpl to implement a service named Foo). Then implement an
+// InterfaceFactory<Foo> that binds instances of FooImpl to
+// InterfaceRequest<Foo>s and register that on the connection like this:
+//
+// connection->AddService(&factory);
+//
+// Or, if you have multiple factories implemented by the same type, explicitly
+// specify the interface to register the factory for:
+//
+// connection->AddService<Foo>(&my_foo_and_bar_factory_);
+// connection->AddService<Bar>(&my_foo_and_bar_factory_);
+//
+// The InterfaceFactory must outlive the ApplicationConnection.
+//
+// Additionally you specify a ServiceConnector. If a ServiceConnector has
+// been set and an InterfaceFactory has not been registered for the interface
+// request, than the interface request is sent to the ServiceConnector.
+//
+// Just as with InterfaceFactory, ServiceConnector must outlive
+// ApplicationConnection.
+//
+// An ApplicationConnection's lifetime is managed by an ApplicationImpl. To
+// close a connection, call CloseConnection which will destroy this object.
+class ApplicationConnection {
+ public:
+ virtual ~ApplicationConnection() {}
+
+ class TestApi {
+ public:
+ explicit TestApi(ApplicationConnection* connection)
+ : connection_(connection) {
+ }
+ base::WeakPtr<ApplicationConnection> GetWeakPtr() {
+ return connection_->GetWeakPtr();
+ }
+
+ private:
+ ApplicationConnection* connection_;
+ };
+
+ // See class description for details.
+ virtual void SetServiceConnector(ServiceConnector* connector) = 0;
+
+ // Makes Interface available as a service to the remote application.
+ // |factory| will create implementations of Interface on demand.
+ // Returns true if the service was exposed, false if capability filtering
+ // from the shell prevented the service from being exposed.
+ template <typename Interface>
+ bool AddService(InterfaceFactory<Interface>* factory) {
+ return SetServiceConnectorForName(
+ new internal::InterfaceFactoryConnector<Interface>(factory),
+ Interface::Name_);
+ }
+
+ // Binds |ptr| to an implemention of Interface in the remote application.
+ // |ptr| can immediately be used to start sending requests to the remote
+ // service.
+ template <typename Interface>
+ void ConnectToService(InterfacePtr<Interface>* ptr) {
+ if (ServiceProvider* sp = GetServiceProvider()) {
+ MessagePipe pipe;
+ ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u));
+ sp->ConnectToService(Interface::Name_, std::move(pipe.handle1));
+ }
+ }
+
+ // Returns the URL that was used by the source application to establish a
+ // connection to the destination application.
+ //
+ // When ApplicationConnection is representing an incoming connection this can
+ // be different than the URL the application was initially loaded from, if the
+ // application handles multiple URLs. Note that this is the URL after all
+ // URL rewriting and HTTP redirects have been performed.
+ //
+ // When ApplicationConnection is representing and outgoing connection, this
+ // will be the same as the value returned by GetRemoveApplicationURL().
+ virtual const std::string& GetConnectionURL() = 0;
+
+ // Returns the URL identifying the remote application on this connection.
+ virtual const std::string& GetRemoteApplicationURL() = 0;
+
+ // Returns the raw proxy to the remote application's ServiceProvider
+ // interface. Most applications will just use ConnectToService() instead.
+ // Caller does not take ownership.
+ virtual ServiceProvider* GetServiceProvider() = 0;
+
+ // Returns the local application's ServiceProvider interface. The return
+ // value is owned by this connection.
+ virtual ServiceProvider* GetLocalServiceProvider() = 0;
+
+ // Register a handler to receive an error notification on the pipe to the
+ // remote application's service provider.
+ virtual void SetRemoteServiceProviderConnectionErrorHandler(
+ const Closure& handler) = 0;
+
+ // Returns the id of the deepest content handler used in connecting to
+ // the application. If the content handler id has not yet been determined
+ // this returns false, use AddContentHandlerIDCallback() to schedule a
+ // callback when the content handler is has been obtained. A value of 0
+ // indicates no content handler was used in connecting to the application.
+ virtual bool GetContentHandlerID(uint32_t* content_handler_id) = 0;
+
+ // See description in GetTargetID(). If the id of the content handler has
+ // been obtained |callback| is run immediately.
+ virtual void AddContentHandlerIDCallback(const Closure& callback) = 0;
+
+ protected:
+ // Returns true if the connector was set, false if it was not set (e.g. by
+ // some filtering policy preventing this interface from being exposed).
+ virtual bool SetServiceConnectorForName(ServiceConnector* service_connector,
+ const std::string& name) = 0;
+
+ virtual base::WeakPtr<ApplicationConnection> GetWeakPtr() = 0;
+};
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_APPLICATION_CONNECTION_H_
diff --git a/mojo/shell/public/cpp/application_delegate.h b/mojo/shell/public/cpp/application_delegate.h
new file mode 100644
index 0000000..219091f
--- /dev/null
+++ b/mojo/shell/public/cpp/application_delegate.h
@@ -0,0 +1,54 @@
+// 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_SHELL_PUBLIC_CPP_APPLICATION_DELEGATE_H_
+#define MOJO_SHELL_PUBLIC_CPP_APPLICATION_DELEGATE_H_
+
+#include <string>
+
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+class ApplicationConnection;
+class ApplicationImpl;
+
+// An abstract class that the application may subclass to control various
+// behaviors of ApplicationImpl.
+class ApplicationDelegate {
+ public:
+ ApplicationDelegate();
+ virtual ~ApplicationDelegate();
+
+ // Called exactly once before any other method.
+ virtual void Initialize(ApplicationImpl* app);
+
+ // Override this method to configure what services a connection supports when
+ // being connected to from an app.
+ // Return false to reject the connection entirely.
+ virtual bool ConfigureIncomingConnection(ApplicationConnection* connection);
+
+ // Override this method to configure what services a connection supports when
+ // connecting to another app.
+ // Return false to reject the connection entirely.
+ virtual bool ConfigureOutgoingConnection(ApplicationConnection* connection);
+
+ // Called when the shell connection has a connection error.
+ //
+ // Return true to shutdown the application. Return false to skip shutting
+ // down the connection, but user is then required to call
+ // ApplicationImpl::QuitNow() when done.
+ virtual bool OnShellConnectionError();
+
+ // Called before ApplicationImpl::Terminate(). After returning from this call
+ // the delegate can no longer rely on the main run loop still running.
+ virtual void Quit();
+
+ private:
+ MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationDelegate);
+};
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_APPLICATION_DELEGATE_H_
diff --git a/mojo/shell/public/cpp/application_impl.h b/mojo/shell/public/cpp/application_impl.h
new file mode 100644
index 0000000..3853bab
--- /dev/null
+++ b/mojo/shell/public/cpp/application_impl.h
@@ -0,0 +1,186 @@
+// 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_SHELL_PUBLIC_CPP_APPLICATION_IMPL_H_
+#define MOJO_SHELL_PUBLIC_CPP_APPLICATION_IMPL_H_
+
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/callback.h"
+#include "mojo/public/cpp/system/core.h"
+#include "mojo/shell/public/cpp/app_lifetime_helper.h"
+#include "mojo/shell/public/cpp/application_connection.h"
+#include "mojo/shell/public/cpp/application_delegate.h"
+#include "mojo/shell/public/cpp/lib/service_registry.h"
+#include "mojo/shell/public/interfaces/application.mojom.h"
+#include "mojo/shell/public/interfaces/shell.mojom.h"
+
+namespace mojo {
+
+CapabilityFilterPtr CreatePermissiveCapabilityFilter();
+
+// TODO(beng): This comment is hilariously out of date.
+// Utility class for communicating with the Shell, and providing Services
+// to clients.
+//
+// To use define a class that implements your specific server api, e.g. FooImpl
+// to implement a service named Foo.
+// That class must subclass an InterfaceImpl specialization.
+//
+// If there is context that is to be shared amongst all instances, define a
+// constructor with that class as its only argument, otherwise define an empty
+// constructor.
+//
+// class FooImpl : public InterfaceImpl<Foo> {
+// public:
+// FooImpl(ApplicationContext* app_context) {}
+// };
+//
+// or
+//
+// class BarImpl : public InterfaceImpl<Bar> {
+// public:
+// // contexts will remain valid for the lifetime of BarImpl.
+// BarImpl(ApplicationContext* app_context, BarContext* service_context)
+// : app_context_(app_context), servicecontext_(context) {}
+//
+// Create an ApplicationImpl instance that collects any service implementations.
+//
+// ApplicationImpl app(service_provider_handle);
+// app.AddService<FooImpl>();
+//
+// BarContext context;
+// app.AddService<BarImpl>(&context);
+//
+//
+class ApplicationImpl : public Application {
+ public:
+ class ConnectParams {
+ public:
+ explicit ConnectParams(const std::string& url);
+ explicit ConnectParams(URLRequestPtr request);
+ ~ConnectParams();
+
+ URLRequestPtr TakeRequest() { return std::move(request_); }
+ CapabilityFilterPtr TakeFilter() { return std::move(filter_); }
+ void set_filter(CapabilityFilterPtr filter) { filter_ = std::move(filter); }
+
+ private:
+ URLRequestPtr request_;
+ CapabilityFilterPtr filter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectParams);
+ };
+
+ class TestApi {
+ public:
+ explicit TestApi(ApplicationImpl* application)
+ : application_(application) {}
+
+ void UnbindConnections(InterfaceRequest<Application>* application_request,
+ ShellPtr* shell) {
+ application_->UnbindConnections(application_request, shell);
+ }
+
+ private:
+ ApplicationImpl* application_;
+ };
+
+ // Does not take ownership of |delegate|, which must remain valid for the
+ // lifetime of ApplicationImpl.
+ ApplicationImpl(ApplicationDelegate* delegate,
+ InterfaceRequest<Application> request);
+ // Constructs an ApplicationImpl with a custom termination closure. This
+ // closure is invoked on Quit() instead of the default behavior of quitting
+ // the current base::MessageLoop.
+ ApplicationImpl(ApplicationDelegate* delegate,
+ InterfaceRequest<Application> request,
+ const Closure& termination_closure);
+ ~ApplicationImpl() override;
+
+ // The Mojo shell. This will return a valid pointer after Initialize() has
+ // been invoked. It will remain valid until UnbindConnections() is invoked or
+ // the ApplicationImpl is destroyed.
+ Shell* shell() const { return shell_.get(); }
+
+ const std::string& url() const { return url_; }
+
+ AppLifetimeHelper* app_lifetime_helper() { return &app_lifetime_helper_; }
+
+ // Requests a new connection to an application. Returns a pointer to the
+ // connection if the connection is permitted by this application's delegate,
+ // or nullptr otherwise. Caller takes ownership.
+ scoped_ptr<ApplicationConnection> ConnectToApplication(
+ const std::string& url);
+ scoped_ptr<ApplicationConnection> ConnectToApplication(ConnectParams* params);
+
+ // Connect to application identified by |request->url| and connect to the
+ // service implementation of the interface identified by |Interface|.
+ template <typename Interface>
+ void ConnectToService(ConnectParams* params, InterfacePtr<Interface>* ptr) {
+ scoped_ptr<ApplicationConnection> connection = ConnectToApplication(params);
+ if (!connection.get())
+ return;
+ connection->ConnectToService(ptr);
+ }
+ template <typename Interface>
+ void ConnectToService(const std::string& url, InterfacePtr<Interface>* ptr) {
+ ConnectParams params(url);
+ params.set_filter(CreatePermissiveCapabilityFilter());
+ return ConnectToService(&params, ptr);
+ }
+
+ // Block the calling thread until the Initialize() method is called by the
+ // shell.
+ void WaitForInitialize();
+
+ // Initiate shutdown of this application. This may involve a round trip to the
+ // Shell to ensure there are no inbound service requests.
+ void Quit();
+
+ private:
+ // Application implementation.
+ void Initialize(ShellPtr shell, const mojo::String& url) override;
+ void AcceptConnection(const String& requestor_url,
+ InterfaceRequest<ServiceProvider> services,
+ ServiceProviderPtr exposed_services,
+ Array<String> allowed_interfaces,
+ const String& url) override;
+ void OnQuitRequested(const Callback<void(bool)>& callback) override;
+
+ void OnConnectionError();
+
+ // Called from Quit() when there is no Shell connection, or asynchronously
+ // from Quit() once the Shell has OK'ed shutdown.
+ void QuitNow();
+
+ // Unbinds the Shell and Application connections. Can be used to re-bind the
+ // handles to another implementation of ApplicationImpl, for instance when
+ // running apptests.
+ void UnbindConnections(InterfaceRequest<Application>* application_request,
+ ShellPtr* shell);
+
+ // We track the lifetime of incoming connection registries as it more
+ // convenient for the client.
+ ScopedVector<ApplicationConnection> incoming_connections_;
+ ApplicationDelegate* delegate_;
+ Binding<Application> binding_;
+ ShellPtr shell_;
+ std::string url_;
+ Closure termination_closure_;
+ AppLifetimeHelper app_lifetime_helper_;
+ bool quit_requested_;
+ base::WeakPtrFactory<ApplicationImpl> weak_factory_;
+
+ MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationImpl);
+};
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_APPLICATION_IMPL_H_
diff --git a/mojo/shell/public/cpp/application_runner.h b/mojo/shell/public/cpp/application_runner.h
new file mode 100644
index 0000000..10eb0a7
--- /dev/null
+++ b/mojo/shell/public/cpp/application_runner.h
@@ -0,0 +1,63 @@
+// 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_SHELL_PUBLIC_CPP_APPLICATION_RUNNER_H_
+#define MOJO_SHELL_PUBLIC_CPP_APPLICATION_RUNNER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/public/cpp/system/core.h"
+
+namespace mojo {
+
+class ApplicationDelegate;
+
+// A utility for running a chromium based mojo Application. The typical use
+// case is to use when writing your MojoMain:
+//
+// MojoResult MojoMain(MojoHandle shell_handle) {
+// mojo::ApplicationRunner runner(new MyDelegate());
+// return runner.Run(shell_handle);
+// }
+//
+// ApplicationRunner takes care of chromium environment initialization and
+// shutdown, and starting a MessageLoop from which your application can run and
+// ultimately Quit().
+class ApplicationRunner {
+ public:
+ // Takes ownership of |delegate|.
+ explicit ApplicationRunner(ApplicationDelegate* delegate);
+ ~ApplicationRunner();
+
+ static void InitBaseCommandLine();
+
+ void set_message_loop_type(base::MessageLoop::Type type);
+
+ // Once the various parameters have been set above, use Run to initialize an
+ // ApplicationImpl wired to the provided delegate, and run a MessageLoop until
+ // the application exits.
+ //
+ // Iff |init_base| is true, the runner will perform some initialization of
+ // base globals (e.g. CommandLine and AtExitManager) before starting the
+ // application.
+ MojoResult Run(MojoHandle shell_handle, bool init_base);
+
+ // Calls Run above with |init_base| set to |true|.
+ MojoResult Run(MojoHandle shell_handle);
+
+ private:
+ scoped_ptr<ApplicationDelegate> delegate_;
+
+ // MessageLoop type. TYPE_CUSTOM is default (MessagePumpMojo will be used as
+ // the underlying message pump).
+ base::MessageLoop::Type message_loop_type_;
+ // Whether Run() has been called.
+ bool has_run_;
+
+ MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationRunner);
+};
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_APPLICATION_RUNNER_H_
diff --git a/mojo/shell/public/cpp/application_test_base.h b/mojo/shell/public/cpp/application_test_base.h
new file mode 100644
index 0000000..55b9ea9
--- /dev/null
+++ b/mojo/shell/public/cpp/application_test_base.h
@@ -0,0 +1,59 @@
+// 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_SHELL_PUBLIC_CPP_APPLICATION_TEST_BASE_H_
+#define MOJO_SHELL_PUBLIC_CPP_APPLICATION_TEST_BASE_H_
+
+#include "mojo/public/cpp/bindings/array.h"
+#include "mojo/public/cpp/bindings/string.h"
+#include "mojo/public/cpp/system/macros.h"
+#include "mojo/shell/public/cpp/application_delegate.h"
+#include "mojo/shell/public/interfaces/application.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+
+class ApplicationImpl;
+
+namespace test {
+
+// Run all application tests. This must be called after the environment is
+// initialized, to support construction of a default run loop.
+MojoResult RunAllTests(MojoHandle application_request_handle);
+
+// A GTEST base class for application testing executed in mojo_shell.
+class ApplicationTestBase : public testing::Test {
+ public:
+ ApplicationTestBase();
+ ~ApplicationTestBase() override;
+
+ protected:
+ ApplicationImpl* application_impl() { return application_impl_; }
+
+ // Get the ApplicationDelegate for the application to be tested.
+ virtual ApplicationDelegate* GetApplicationDelegate();
+
+ // testing::Test:
+ void SetUp() override;
+ void TearDown() override;
+
+ // True by default, which indicates a MessageLoop will automatically be
+ // created for the application. Tests may override this function to prevent
+ // a default loop from being created.
+ virtual bool ShouldCreateDefaultRunLoop();
+
+ private:
+ // The application implementation instance, reconstructed for each test.
+ ApplicationImpl* application_impl_;
+ // The application delegate used if GetApplicationDelegate is not overridden.
+ ApplicationDelegate default_application_delegate_;
+
+ MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationTestBase);
+};
+
+} // namespace test
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_APPLICATION_TEST_BASE_H_
diff --git a/mojo/shell/public/cpp/connect.h b/mojo/shell/public/cpp/connect.h
new file mode 100644
index 0000000..acc496c
--- /dev/null
+++ b/mojo/shell/public/cpp/connect.h
@@ -0,0 +1,25 @@
+// 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_SHELL_PUBLIC_CPP_CONNECT_H_
+#define MOJO_SHELL_PUBLIC_CPP_CONNECT_H_
+
+#include <utility>
+
+#include "mojo/shell/public/interfaces/service_provider.mojom.h"
+
+namespace mojo {
+
+// Binds |ptr| to a remote implementation of Interface from |service_provider|.
+template <typename Interface>
+inline void ConnectToService(ServiceProvider* service_provider,
+ InterfacePtr<Interface>* ptr) {
+ MessagePipe pipe;
+ ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u));
+ service_provider->ConnectToService(Interface::Name_, std::move(pipe.handle1));
+}
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_CONNECT_H_
diff --git a/mojo/shell/public/cpp/content_handler_factory.h b/mojo/shell/public/cpp/content_handler_factory.h
new file mode 100644
index 0000000..4bcb81e
--- /dev/null
+++ b/mojo/shell/public/cpp/content_handler_factory.h
@@ -0,0 +1,81 @@
+// 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_SHELL_PUBLIC_CPP_CONTENT_HANDLER_FACTORY_H_
+#define MOJO_SHELL_PUBLIC_CPP_CONTENT_HANDLER_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "mojo/services/network/public/interfaces/url_loader.mojom.h"
+#include "mojo/shell/public/cpp/interface_factory.h"
+#include "mojo/shell/public/interfaces/content_handler.mojom.h"
+#include "mojo/shell/public/interfaces/shell.mojom.h"
+
+namespace mojo {
+
+class ContentHandlerFactory : public InterfaceFactory<ContentHandler> {
+ public:
+ class HandledApplicationHolder {
+ public:
+ virtual ~HandledApplicationHolder() {}
+ };
+
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+ // Implement this method to create the Application. This method will be
+ // called on a new thread. Leaving this method will quit the application.
+ virtual void RunApplication(
+ InterfaceRequest<Application> application_request,
+ URLResponsePtr response) = 0;
+ };
+
+ class ManagedDelegate : public Delegate {
+ public:
+ ~ManagedDelegate() override {}
+ // Implement this method to create the Application for the given content.
+ // This method will be called on a new thread. The application will be run
+ // on this new thread, and the returned value will be kept alive until the
+ // application ends.
+ virtual scoped_ptr<HandledApplicationHolder> CreateApplication(
+ InterfaceRequest<Application> application_request,
+ URLResponsePtr response) = 0;
+
+ private:
+ void RunApplication(InterfaceRequest<Application> application_request,
+ URLResponsePtr response) override;
+ };
+
+ explicit ContentHandlerFactory(Delegate* delegate);
+ ~ContentHandlerFactory() override;
+
+ private:
+ // From InterfaceFactory:
+ void Create(ApplicationConnection* connection,
+ InterfaceRequest<ContentHandler> request) override;
+
+ Delegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentHandlerFactory);
+};
+
+template <class A>
+class HandledApplicationHolderImpl
+ : public ContentHandlerFactory::HandledApplicationHolder {
+ public:
+ explicit HandledApplicationHolderImpl(A* value) : value_(value) {}
+
+ private:
+ scoped_ptr<A> value_;
+};
+
+template <class A>
+scoped_ptr<ContentHandlerFactory::HandledApplicationHolder>
+make_handled_factory_holder(A* value) {
+ return make_scoped_ptr(new HandledApplicationHolderImpl<A>(value));
+}
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_CONTENT_HANDLER_FACTORY_H_
diff --git a/mojo/shell/public/cpp/initialize_base_and_icu.cc b/mojo/shell/public/cpp/initialize_base_and_icu.cc
new file mode 100644
index 0000000..2ec37df
--- /dev/null
+++ b/mojo/shell/public/cpp/initialize_base_and_icu.cc
@@ -0,0 +1,50 @@
+// 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.
+
+// This file declares a raw symbol and should be included only once in a
+// certain binary target. This needs to be run before we raise the sandbox,
+// which means that it can't use mojo. Our runners will dig around in the
+// symbol table and run this before the mojo system is initialized.
+
+#include <stdint.h>
+
+#include "base/files/file.h"
+#include "base/i18n/icu_util.h"
+#include "base/rand_util.h"
+#include "base/sys_info.h"
+#include "mojo/public/c/system/types.h"
+
+#if !defined(OS_ANDROID)
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+#endif
+
+extern "C" {
+#if defined(WIN32)
+__declspec(dllexport) void __cdecl
+#else
+void __attribute__((visibility("default")))
+#endif
+InitializeBase(const uint8_t* icu_data) {
+ base::RandUint64();
+ base::SysInfo::AmountOfPhysicalMemory();
+ base::SysInfo::NumberOfProcessors();
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ base::SysInfo::MaxSharedMemorySize();
+#endif
+
+ // Initialize core ICU. We must perform the full initialization before we
+ // initialize icu::TimeZone subsystem because otherwise ICU gets in a state
+ // where the timezone data is disconnected from the locale data which can
+ // cause crashes.
+ CHECK(base::i18n::InitializeICUFromRawMemory(icu_data));
+
+#if !defined(OS_ANDROID)
+ // ICU DateFormat class (used in base/time_format.cc) needs to get the
+ // Olson timezone ID by accessing the zoneinfo files on disk. After
+ // TimeZone::createDefault is called once here, the timezone ID is
+ // cached and there's no more need to access the file system.
+ scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+#endif
+}
+}
diff --git a/mojo/shell/public/cpp/interface_factory.h b/mojo/shell/public/cpp/interface_factory.h
new file mode 100644
index 0000000..7f8f26e
--- /dev/null
+++ b/mojo/shell/public/cpp/interface_factory.h
@@ -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.
+
+#ifndef MOJO_SHELL_PUBLIC_CPP_INTERFACE_FACTORY_H_
+#define MOJO_SHELL_PUBLIC_CPP_INTERFACE_FACTORY_H_
+
+#include "mojo/public/cpp/bindings/interface_request.h"
+
+namespace mojo {
+
+class ApplicationConnection;
+template <typename Interface>
+class InterfaceRequest;
+
+// Implement this class to provide implementations of a given interface and
+// bind them to incoming requests. The implementation of this class is
+// responsible for managing the lifetime of the implementations of the
+// interface.
+template <typename Interface>
+class InterfaceFactory {
+ public:
+ virtual ~InterfaceFactory() {}
+ virtual void Create(ApplicationConnection* connection,
+ InterfaceRequest<Interface> request) = 0;
+};
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_INTERFACE_FACTORY_H_
diff --git a/mojo/shell/public/cpp/interface_factory_impl.h b/mojo/shell/public/cpp/interface_factory_impl.h
new file mode 100644
index 0000000..7de2449
--- /dev/null
+++ b/mojo/shell/public/cpp/interface_factory_impl.h
@@ -0,0 +1,49 @@
+// 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_SHELL_PUBLIC_CPP_INTERFACE_FACTORY_IMPL_H_
+#define MOJO_SHELL_PUBLIC_CPP_INTERFACE_FACTORY_IMPL_H_
+
+#include "mojo/shell/public/cpp/interface_factory.h"
+
+namespace mojo {
+
+// Use this class to allocate and bind instances of Impl to interface requests.
+// The lifetime of the constructed Impl is bound to the pipe.
+template <typename Impl,
+ typename Interface = typename Impl::ImplementedInterface>
+class InterfaceFactoryImpl : public InterfaceFactory<Interface> {
+ public:
+ virtual ~InterfaceFactoryImpl() {}
+
+ virtual void Create(ApplicationConnection* connection,
+ InterfaceRequest<Interface> request) override {
+ BindToRequest(new Impl(), &request);
+ }
+};
+
+// Use this class to allocate and bind instances of Impl constructed with a
+// context parameter to interface requests. The lifetime of the constructed
+// Impl is bound to the pipe.
+template <typename Impl,
+ typename Context,
+ typename Interface = typename Impl::ImplementedInterface>
+class InterfaceFactoryImplWithContext : public InterfaceFactory<Interface> {
+ public:
+ explicit InterfaceFactoryImplWithContext(Context* context)
+ : context_(context) {}
+ virtual ~InterfaceFactoryImplWithContext() {}
+
+ virtual void Create(ApplicationConnection* connection,
+ InterfaceRequest<Interface> request) override {
+ BindToRequest(new Impl(context_), &request);
+ }
+
+ private:
+ Context* context_;
+};
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_INTERFACE_FACTORY_IMPL_H_
diff --git a/mojo/shell/public/cpp/lazy_interface_ptr.h b/mojo/shell/public/cpp/lazy_interface_ptr.h
new file mode 100644
index 0000000..0497dc2
--- /dev/null
+++ b/mojo/shell/public/cpp/lazy_interface_ptr.h
@@ -0,0 +1,46 @@
+// 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_SHELL_PUBLIC_CPP_LAZY_INTERFACE_PTR_H_
+#define MOJO_SHELL_PUBLIC_CPP_LAZY_INTERFACE_PTR_H_
+
+#include "mojo/shell/public/cpp/connect.h"
+#include "mojo/shell/public/interfaces/service_provider.mojom.h"
+
+namespace mojo {
+
+// An InterfacePtr that will request an implementation from a specified
+// ServiceProvider when it is first accessed with the get() method.
+template <typename Interface>
+class LazyInterfacePtr : public InterfacePtr<Interface> {
+ public:
+ LazyInterfacePtr() : service_provider_(nullptr) {}
+
+ explicit LazyInterfacePtr(ServiceProvider* service_provider)
+ : service_provider_(service_provider) {}
+
+ void set_service_provider(ServiceProvider* service_provider) {
+ if (service_provider != service_provider_) {
+ InterfacePtr<Interface>::reset();
+ }
+ service_provider_ = service_provider;
+ }
+
+ Interface* get() const {
+ if (!InterfacePtr<Interface>::get() && service_provider_) {
+ mojo::ConnectToService<Interface>(
+ service_provider_, const_cast<LazyInterfacePtr<Interface>*>(this));
+ }
+ return InterfacePtr<Interface>::get();
+ }
+ Interface* operator->() const { return get(); }
+ Interface& operator*() const { return *get(); }
+
+ private:
+ ServiceProvider* service_provider_;
+};
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_LAZY_INTERFACE_PTR_H_
diff --git a/mojo/shell/public/cpp/lib/app_lifetime_helper.cc b/mojo/shell/public/cpp/lib/app_lifetime_helper.cc
new file mode 100644
index 0000000..0772412a
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/app_lifetime_helper.cc
@@ -0,0 +1,94 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/shell/public/cpp/app_lifetime_helper.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/shell/public/cpp/application_impl.h"
+
+namespace mojo {
+
+AppRefCount::AppRefCount(
+ AppLifetimeHelper* app_lifetime_helper,
+ scoped_refptr<base::SingleThreadTaskRunner> app_task_runner)
+ : app_lifetime_helper_(app_lifetime_helper),
+ app_task_runner_(app_task_runner) {
+}
+
+AppRefCount::~AppRefCount() {
+#ifndef NDEBUG
+ // Ensure that this object is used on only one thread at a time, or else there
+ // could be races where the object is being reset on one thread and cloned on
+ // another.
+ if (clone_task_runner_) {
+ DCHECK(clone_task_runner_->BelongsToCurrentThread());
+ }
+#endif
+
+ if (app_task_runner_->BelongsToCurrentThread()) {
+ app_lifetime_helper_->Release();
+ return;
+ }
+
+ app_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppLifetimeHelper::Release,
+ base::Unretained(app_lifetime_helper_)));
+}
+
+scoped_ptr<AppRefCount> AppRefCount::Clone() {
+ if (app_task_runner_->BelongsToCurrentThread()) {
+ app_lifetime_helper_->AddRef();
+ } else {
+ app_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppLifetimeHelper::AddRef,
+ base::Unretained(app_lifetime_helper_)));
+ }
+
+#ifndef NDEBUG
+ // Ensure that this object is used on only one thread at a time, or else there
+ // could be races where the object is being reset on one thread and cloned on
+ // another.
+ if (clone_task_runner_) {
+ DCHECK(clone_task_runner_->BelongsToCurrentThread());
+ } else {
+ clone_task_runner_ = base::MessageLoop::current()->task_runner();
+ }
+#endif
+
+ return make_scoped_ptr(new AppRefCount(
+ app_lifetime_helper_, app_task_runner_));
+}
+
+AppLifetimeHelper::AppLifetimeHelper(ApplicationImpl* app)
+ : app_(app), ref_count_(0) {
+}
+
+AppLifetimeHelper::~AppLifetimeHelper() {
+}
+
+scoped_ptr<AppRefCount> AppLifetimeHelper::CreateAppRefCount() {
+ AddRef();
+ return make_scoped_ptr(new AppRefCount(
+ this, base::MessageLoop::current()->task_runner()));
+}
+
+void AppLifetimeHelper::AddRef() {
+ ref_count_++;
+}
+
+void AppLifetimeHelper::Release() {
+ if (!--ref_count_) {
+ if (app_)
+ app_->Quit();
+ }
+}
+
+void AppLifetimeHelper::OnQuit() {
+ app_ = nullptr;
+}
+
+} // namespace mojo
diff --git a/mojo/shell/public/cpp/lib/application_delegate.cc b/mojo/shell/public/cpp/lib/application_delegate.cc
new file mode 100644
index 0000000..41ba51c
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/application_delegate.cc
@@ -0,0 +1,34 @@
+// 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/shell/public/cpp/application_delegate.h"
+
+namespace mojo {
+
+ApplicationDelegate::ApplicationDelegate() {
+}
+ApplicationDelegate::~ApplicationDelegate() {
+}
+
+void ApplicationDelegate::Initialize(ApplicationImpl* app) {
+}
+
+bool ApplicationDelegate::ConfigureIncomingConnection(
+ ApplicationConnection* connection) {
+ return true;
+}
+
+bool ApplicationDelegate::ConfigureOutgoingConnection(
+ ApplicationConnection* connection) {
+ return true;
+}
+
+bool ApplicationDelegate::OnShellConnectionError() {
+ return true;
+}
+
+void ApplicationDelegate::Quit() {
+}
+
+} // namespace mojo
diff --git a/mojo/shell/public/cpp/lib/application_impl.cc b/mojo/shell/public/cpp/lib/application_impl.cc
new file mode 100644
index 0000000..e48483f
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/application_impl.cc
@@ -0,0 +1,181 @@
+// 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 <algorithm>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/converters/network/network_type_converters.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/shell/public/cpp/application_delegate.h"
+#include "mojo/shell/public/cpp/application_impl.h"
+#include "mojo/shell/public/cpp/lib/service_registry.h"
+
+namespace mojo {
+
+namespace {
+
+void DefaultTerminationClosure() {
+ if (base::MessageLoop::current() &&
+ base::MessageLoop::current()->is_running())
+ base::MessageLoop::current()->QuitWhenIdle();
+}
+
+} // namespace
+
+ApplicationImpl::ConnectParams::ConnectParams(const std::string& url)
+ : ConnectParams(URLRequest::From(url)) {}
+ApplicationImpl::ConnectParams::ConnectParams(URLRequestPtr request)
+ : request_(std::move(request)), filter_(CapabilityFilter::New()) {
+ filter_->filter.mark_non_null();
+}
+ApplicationImpl::ConnectParams::~ConnectParams() {}
+
+ApplicationImpl::ApplicationImpl(ApplicationDelegate* delegate,
+ InterfaceRequest<Application> request)
+ : ApplicationImpl(delegate,
+ std::move(request),
+ base::Bind(&DefaultTerminationClosure)) {}
+
+ApplicationImpl::ApplicationImpl(ApplicationDelegate* delegate,
+ InterfaceRequest<Application> request,
+ const Closure& termination_closure)
+ : delegate_(delegate),
+ binding_(this, std::move(request)),
+ termination_closure_(termination_closure),
+ app_lifetime_helper_(this),
+ quit_requested_(false),
+ weak_factory_(this) {}
+
+ApplicationImpl::~ApplicationImpl() {
+ app_lifetime_helper_.OnQuit();
+}
+
+scoped_ptr<ApplicationConnection> ApplicationImpl::ConnectToApplication(
+ const std::string& url) {
+ ConnectParams params(url);
+ params.set_filter(CreatePermissiveCapabilityFilter());
+ return ConnectToApplication(&params);
+}
+
+scoped_ptr<ApplicationConnection>
+ ApplicationImpl::ConnectToApplication(ConnectParams* params) {
+ if (!shell_)
+ return nullptr;
+ DCHECK(params);
+ URLRequestPtr request = params->TakeRequest();
+ ServiceProviderPtr local_services;
+ InterfaceRequest<ServiceProvider> local_request = GetProxy(&local_services);
+ ServiceProviderPtr remote_services;
+ std::string application_url = request->url.To<std::string>();
+ // We allow all interfaces on outgoing connections since we are presumably in
+ // a position to know who we're talking to.
+ // TODO(beng): is this a valid assumption or do we need to figure some way to
+ // filter here too?
+ std::set<std::string> allowed;
+ allowed.insert("*");
+ InterfaceRequest<ServiceProvider> remote_services_proxy =
+ GetProxy(&remote_services);
+ scoped_ptr<internal::ServiceRegistry> registry(new internal::ServiceRegistry(
+ application_url, application_url, std::move(remote_services),
+ std::move(local_request), allowed));
+ shell_->ConnectToApplication(std::move(request),
+ std::move(remote_services_proxy),
+ std::move(local_services), params->TakeFilter(),
+ registry->GetConnectToApplicationCallback());
+ if (!delegate_->ConfigureOutgoingConnection(registry.get()))
+ return nullptr;
+ return std::move(registry);
+}
+
+void ApplicationImpl::WaitForInitialize() {
+ DCHECK(!shell_.is_bound());
+ binding_.WaitForIncomingMethodCall();
+}
+
+void ApplicationImpl::Quit() {
+ // We can't quit immediately, since there could be in-flight requests from the
+ // shell. So check with it first.
+ if (shell_) {
+ quit_requested_ = true;
+ shell_->QuitApplication();
+ } else {
+ QuitNow();
+ }
+}
+
+void ApplicationImpl::Initialize(ShellPtr shell, const mojo::String& url) {
+ shell_ = std::move(shell);
+ shell_.set_connection_error_handler([this]() { OnConnectionError(); });
+ url_ = url;
+ delegate_->Initialize(this);
+}
+
+void ApplicationImpl::AcceptConnection(
+ const String& requestor_url,
+ InterfaceRequest<ServiceProvider> services,
+ ServiceProviderPtr exposed_services,
+ Array<String> allowed_interfaces,
+ const String& url) {
+ scoped_ptr<ApplicationConnection> registry(new internal::ServiceRegistry(
+ url, requestor_url, std::move(exposed_services), std::move(services),
+ allowed_interfaces.To<std::set<std::string>>()));
+ if (!delegate_->ConfigureIncomingConnection(registry.get()))
+ return;
+
+ // If we were quitting because we thought there were no more services for this
+ // app in use, then that has changed so cancel the quit request.
+ if (quit_requested_)
+ quit_requested_ = false;
+
+ incoming_connections_.push_back(std::move(registry));
+}
+
+void ApplicationImpl::OnQuitRequested(const Callback<void(bool)>& callback) {
+ // If by the time we got the reply from the shell, more requests had come in
+ // then we don't want to quit the app anymore so we return false. Otherwise
+ // |quit_requested_| is true so we tell the shell to proceed with the quit.
+ callback.Run(quit_requested_);
+ if (quit_requested_)
+ QuitNow();
+}
+
+void ApplicationImpl::OnConnectionError() {
+ base::WeakPtr<ApplicationImpl> ptr(weak_factory_.GetWeakPtr());
+
+ // We give the delegate notice first, since it might want to do something on
+ // shell connection errors other than immediate termination of the run
+ // loop. The application might want to continue servicing connections other
+ // than the one to the shell.
+ bool quit_now = delegate_->OnShellConnectionError();
+ if (quit_now)
+ QuitNow();
+ if (!ptr)
+ return;
+ shell_ = nullptr;
+}
+
+void ApplicationImpl::QuitNow() {
+ delegate_->Quit();
+ termination_closure_.Run();
+}
+
+void ApplicationImpl::UnbindConnections(
+ InterfaceRequest<Application>* application_request,
+ ShellPtr* shell) {
+ *application_request = binding_.Unbind();
+ shell->Bind(shell_.PassInterface());
+}
+
+CapabilityFilterPtr CreatePermissiveCapabilityFilter() {
+ CapabilityFilterPtr filter(CapabilityFilter::New());
+ Array<String> all_interfaces;
+ all_interfaces.push_back("*");
+ filter->filter.insert("*", std::move(all_interfaces));
+ return filter;
+}
+
+} // namespace mojo
diff --git a/mojo/shell/public/cpp/lib/application_runner.cc b/mojo/shell/public/cpp/lib/application_runner.cc
new file mode 100644
index 0000000..02380c6
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/application_runner.cc
@@ -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.
+
+#include "mojo/shell/public/cpp/application_runner.h"
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/process/launch.h"
+#include "mojo/message_pump/message_pump_mojo.h"
+#include "mojo/shell/public/cpp/application_delegate.h"
+#include "mojo/shell/public/cpp/application_impl.h"
+
+namespace mojo {
+
+int g_application_runner_argc;
+const char* const* g_application_runner_argv;
+
+ApplicationRunner::ApplicationRunner(ApplicationDelegate* delegate)
+ : delegate_(scoped_ptr<ApplicationDelegate>(delegate)),
+ message_loop_type_(base::MessageLoop::TYPE_CUSTOM),
+ has_run_(false) {}
+
+ApplicationRunner::~ApplicationRunner() {}
+
+void ApplicationRunner::InitBaseCommandLine() {
+ base::CommandLine::Init(g_application_runner_argc, g_application_runner_argv);
+}
+
+void ApplicationRunner::set_message_loop_type(base::MessageLoop::Type type) {
+ DCHECK_NE(base::MessageLoop::TYPE_CUSTOM, type);
+ DCHECK(!has_run_);
+
+ message_loop_type_ = type;
+}
+
+MojoResult ApplicationRunner::Run(MojoHandle application_request_handle,
+ bool init_base) {
+ DCHECK(!has_run_);
+ has_run_ = true;
+
+ scoped_ptr<base::AtExitManager> at_exit;
+ if (init_base) {
+ InitBaseCommandLine();
+ at_exit.reset(new base::AtExitManager);
+ }
+
+ {
+ scoped_ptr<base::MessageLoop> loop;
+ if (message_loop_type_ == base::MessageLoop::TYPE_CUSTOM)
+ loop.reset(new base::MessageLoop(common::MessagePumpMojo::Create()));
+ else
+ loop.reset(new base::MessageLoop(message_loop_type_));
+
+ ApplicationImpl impl(delegate_.get(),
+ MakeRequest<Application>(MakeScopedHandle(
+ MessagePipeHandle(application_request_handle))));
+ loop->Run();
+ // It's very common for the delegate to cache the app and terminate on
+ // errors. If we don't delete the delegate before the app we run the risk
+ // of the delegate having a stale reference to the app and trying to use it.
+ // Note that we destruct the message loop first because that might trigger
+ // connection error handlers and they might access objects created by the
+ // delegate.
+ loop.reset();
+ delegate_.reset();
+ }
+ return MOJO_RESULT_OK;
+}
+
+MojoResult ApplicationRunner::Run(MojoHandle application_request_handle) {
+ return Run(application_request_handle, true);
+}
+
+} // namespace mojo
diff --git a/mojo/shell/public/cpp/lib/application_test_base.cc b/mojo/shell/public/cpp/lib/application_test_base.cc
new file mode 100644
index 0000000..d1b2cfa
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/application_test_base.cc
@@ -0,0 +1,158 @@
+// 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 <utility>
+
+#include "base/command_line.h"
+#include "base/strings/utf_string_conversions.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "mojo/shell/public/cpp/application_impl.h"
+#include "mojo/shell/public/cpp/application_test_base.h"
+#include "mojo/shell/public/interfaces/application.mojom.h"
+
+namespace mojo {
+namespace test {
+
+namespace {
+// Share the application URL with multiple application tests.
+String g_url;
+
+// Application request handle passed from the shell in MojoMain, stored in
+// between SetUp()/TearDown() so we can (re-)intialize new ApplicationImpls.
+InterfaceRequest<Application> g_application_request;
+
+// Shell pointer passed in the initial mojo.Application.Initialize() call,
+// stored in between initial setup and the first test and between SetUp/TearDown
+// calls so we can (re-)initialize new ApplicationImpls.
+ShellPtr g_shell;
+
+class ShellGrabber : public Application {
+ public:
+ explicit ShellGrabber(InterfaceRequest<Application> application_request)
+ : binding_(this, std::move(application_request)) {}
+
+ void WaitForInitialize() {
+ // Initialize is always the first call made on Application.
+ MOJO_CHECK(binding_.WaitForIncomingMethodCall());
+ }
+
+ private:
+ // Application implementation.
+ void Initialize(ShellPtr shell, const mojo::String& url) override {
+ g_url = url;
+ g_application_request = binding_.Unbind();
+ g_shell = std::move(shell);
+ }
+
+ void AcceptConnection(const String& requestor_url,
+ InterfaceRequest<ServiceProvider> services,
+ ServiceProviderPtr exposed_services,
+ Array<String> allowed_interfaces,
+ const String& url) override {
+ MOJO_CHECK(false);
+ }
+
+ void OnQuitRequested(const Callback<void(bool)>& callback) override {
+ MOJO_CHECK(false);
+ }
+
+ Binding<Application> binding_;
+};
+
+} // namespace
+
+MojoResult RunAllTests(MojoHandle application_request_handle) {
+ {
+ // This loop is used for init, and then destroyed before running tests.
+ Environment::InstantiateDefaultRunLoop();
+
+ // Grab the shell handle.
+ ShellGrabber grabber(
+ MakeRequest<Application>(MakeScopedHandle(
+ MessagePipeHandle(application_request_handle))));
+ grabber.WaitForInitialize();
+ MOJO_CHECK(g_shell);
+ MOJO_CHECK(g_application_request.is_pending());
+
+ int argc = 0;
+ base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ const char** argv = new const char* [cmd_line->argv().size() + 1];
+#if defined(OS_WIN)
+ std::vector<std::string> local_strings;
+#endif
+ for (auto& arg : cmd_line->argv()) {
+#if defined(OS_WIN)
+ local_strings.push_back(base::WideToUTF8(arg));
+ argv[argc++] = local_strings.back().c_str();
+#else
+ argv[argc++] = arg.c_str();
+#endif
+ }
+ argv[argc] = nullptr;
+
+ testing::InitGoogleTest(&argc, const_cast<char**>(&(argv[0])));
+
+ Environment::DestroyDefaultRunLoop();
+ }
+
+ int result = RUN_ALL_TESTS();
+
+ // Shut down our message pipes before exiting.
+ (void)g_application_request.PassMessagePipe();
+ g_shell.reset();
+
+ return (result == 0) ? MOJO_RESULT_OK : MOJO_RESULT_UNKNOWN;
+}
+
+ApplicationTestBase::ApplicationTestBase() : application_impl_(nullptr) {
+}
+
+ApplicationTestBase::~ApplicationTestBase() {
+}
+
+ApplicationDelegate* ApplicationTestBase::GetApplicationDelegate() {
+ return &default_application_delegate_;
+}
+
+void ApplicationTestBase::SetUp() {
+ // A run loop is recommended for ApplicationImpl initialization and
+ // communication.
+ if (ShouldCreateDefaultRunLoop())
+ Environment::InstantiateDefaultRunLoop();
+
+ MOJO_CHECK(g_application_request.is_pending());
+ MOJO_CHECK(g_shell);
+
+ // New applications are constructed for each test to avoid persisting state.
+ application_impl_ = new ApplicationImpl(GetApplicationDelegate(),
+ std::move(g_application_request));
+
+ // Fake application initialization.
+ Application* application = application_impl_;
+ application->Initialize(std::move(g_shell), g_url);
+}
+
+void ApplicationTestBase::TearDown() {
+ MOJO_CHECK(!g_application_request.is_pending());
+ MOJO_CHECK(!g_shell);
+
+ // TODO: commented out until http://crbug.com/533107 is solved.
+ // {
+ // ApplicationImpl::TestApi test_api(application_impl_);
+ // test_api.UnbindConnections(&g_application_request, &g_shell);
+ // }
+ delete application_impl_;
+ if (ShouldCreateDefaultRunLoop())
+ Environment::DestroyDefaultRunLoop();
+}
+
+bool ApplicationTestBase::ShouldCreateDefaultRunLoop() {
+ return true;
+}
+
+
+} // namespace test
+} // namespace mojo
diff --git a/mojo/shell/public/cpp/lib/application_test_main.cc b/mojo/shell/public/cpp/lib/application_test_main.cc
new file mode 100644
index 0000000..470846c
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/application_test_main.cc
@@ -0,0 +1,23 @@
+// 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/command_line.h"
+#include "base/test/test_timeouts.h"
+#include "mojo/logging/init_logging.h"
+#include "mojo/public/c/system/main.h"
+#include "mojo/shell/public/cpp/application_runner.h"
+#include "mojo/shell/public/cpp/application_test_base.h"
+
+MojoResult MojoMain(MojoHandle handle) {
+ // An AtExitManager instance is needed to construct message loops.
+ base::AtExitManager at_exit;
+
+ // Initialize the current process Commandline and test timeouts.
+ mojo::ApplicationRunner::InitBaseCommandLine();
+ mojo::InitLogging();
+ TestTimeouts::Initialize();
+
+ return mojo::test::RunAllTests(handle);
+}
diff --git a/mojo/shell/public/cpp/lib/content_handler_factory.cc b/mojo/shell/public/cpp/lib/content_handler_factory.cc
new file mode 100644
index 0000000..c810354
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/content_handler_factory.cc
@@ -0,0 +1,143 @@
+// 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 <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+#include "mojo/message_pump/message_pump_mojo.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/shell/public/cpp/application_connection.h"
+#include "mojo/shell/public/cpp/application_delegate.h"
+#include "mojo/shell/public/cpp/application_impl.h"
+#include "mojo/shell/public/cpp/application_runner.h"
+#include "mojo/shell/public/cpp/content_handler_factory.h"
+#include "mojo/shell/public/cpp/interface_factory_impl.h"
+
+namespace mojo {
+
+namespace {
+
+class ApplicationThread : public base::PlatformThread::Delegate {
+ public:
+ ApplicationThread(
+ scoped_refptr<base::SingleThreadTaskRunner> handler_thread,
+ const base::Callback<void(ApplicationThread*)>& termination_callback,
+ ContentHandlerFactory::Delegate* handler_delegate,
+ InterfaceRequest<Application> application_request,
+ URLResponsePtr response,
+ const Callback<void()>& destruct_callback)
+ : handler_thread_(handler_thread),
+ termination_callback_(termination_callback),
+ handler_delegate_(handler_delegate),
+ application_request_(std::move(application_request)),
+ response_(std::move(response)),
+ destruct_callback_(destruct_callback) {}
+
+ ~ApplicationThread() override {
+ destruct_callback_.Run();
+ }
+
+ private:
+ void ThreadMain() override {
+ handler_delegate_->RunApplication(std::move(application_request_),
+ std::move(response_));
+ handler_thread_->PostTask(FROM_HERE,
+ base::Bind(termination_callback_, this));
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner> handler_thread_;
+ base::Callback<void(ApplicationThread*)> termination_callback_;
+ ContentHandlerFactory::Delegate* handler_delegate_;
+ InterfaceRequest<Application> application_request_;
+ URLResponsePtr response_;
+ Callback<void()> destruct_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(ApplicationThread);
+};
+
+class ContentHandlerImpl : public ContentHandler {
+ public:
+ ContentHandlerImpl(ContentHandlerFactory::Delegate* delegate,
+ InterfaceRequest<ContentHandler> request)
+ : delegate_(delegate),
+ binding_(this, std::move(request)),
+ weak_factory_(this) {}
+ ~ContentHandlerImpl() override {
+ // We're shutting down and doing cleanup. Cleanup may trigger calls back to
+ // OnThreadEnd(). As we're doing the cleanup here we don't want to do it in
+ // OnThreadEnd() as well. InvalidateWeakPtrs() ensures we don't get any
+ // calls to OnThreadEnd().
+ weak_factory_.InvalidateWeakPtrs();
+ for (auto thread : active_threads_) {
+ base::PlatformThread::Join(thread.second);
+ delete thread.first;
+ }
+ }
+
+ private:
+ // Overridden from ContentHandler:
+ void StartApplication(
+ InterfaceRequest<Application> application_request,
+ URLResponsePtr response,
+ const Callback<void()>& destruct_callback) override {
+ ApplicationThread* thread =
+ new ApplicationThread(base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&ContentHandlerImpl::OnThreadEnd,
+ weak_factory_.GetWeakPtr()),
+ delegate_, std::move(application_request),
+ std::move(response), destruct_callback);
+ base::PlatformThreadHandle handle;
+ bool launched = base::PlatformThread::Create(0, thread, &handle);
+ DCHECK(launched);
+ active_threads_[thread] = handle;
+ }
+
+ void OnThreadEnd(ApplicationThread* thread) {
+ DCHECK(active_threads_.find(thread) != active_threads_.end());
+ base::PlatformThreadHandle handle = active_threads_[thread];
+ active_threads_.erase(thread);
+ base::PlatformThread::Join(handle);
+ delete thread;
+ }
+
+ ContentHandlerFactory::Delegate* delegate_;
+ std::map<ApplicationThread*, base::PlatformThreadHandle> active_threads_;
+ StrongBinding<ContentHandler> binding_;
+ base::WeakPtrFactory<ContentHandlerImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentHandlerImpl);
+};
+
+} // namespace
+
+ContentHandlerFactory::ContentHandlerFactory(Delegate* delegate)
+ : delegate_(delegate) {
+}
+
+ContentHandlerFactory::~ContentHandlerFactory() {
+}
+
+void ContentHandlerFactory::ManagedDelegate::RunApplication(
+ InterfaceRequest<Application> application_request,
+ URLResponsePtr response) {
+ base::MessageLoop loop(common::MessagePumpMojo::Create());
+ auto application = this->CreateApplication(std::move(application_request),
+ std::move(response));
+ if (application)
+ loop.Run();
+}
+
+void ContentHandlerFactory::Create(ApplicationConnection* connection,
+ InterfaceRequest<ContentHandler> request) {
+ new ContentHandlerImpl(delegate_, std::move(request));
+}
+
+} // namespace mojo
diff --git a/mojo/shell/public/cpp/lib/init_commandline.cc b/mojo/shell/public/cpp/lib/init_commandline.cc
new file mode 100644
index 0000000..a61797b
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/init_commandline.cc
@@ -0,0 +1,22 @@
+// 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 "build/build_config.h"
+
+namespace mojo {
+
+extern int g_application_runner_argc;
+extern const char* const* g_application_runner_argv;
+
+}
+
+#if !defined(OS_WIN)
+extern "C" {
+__attribute__((visibility("default"))) void InitCommandLineArgs(
+ int argc, const char* const* argv) {
+ mojo::g_application_runner_argc = argc;
+ mojo::g_application_runner_argv = argv;
+}
+}
+#endif
diff --git a/mojo/shell/public/cpp/lib/interface_factory_connector.h b/mojo/shell/public/cpp/lib/interface_factory_connector.h
new file mode 100644
index 0000000..5ef7eaa
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/interface_factory_connector.h
@@ -0,0 +1,39 @@
+// 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_SHELL_PUBLIC_CPP_LIB_INTERFACE_FACTORY_CONNECTOR_H_
+#define MOJO_SHELL_PUBLIC_CPP_LIB_INTERFACE_FACTORY_CONNECTOR_H_
+
+#include <utility>
+
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/shell/public/cpp/interface_factory.h"
+#include "mojo/shell/public/cpp/service_connector.h"
+
+namespace mojo {
+namespace internal {
+
+template <typename Interface>
+class InterfaceFactoryConnector : public ServiceConnector {
+ public:
+ explicit InterfaceFactoryConnector(InterfaceFactory<Interface>* factory)
+ : factory_(factory) {}
+ ~InterfaceFactoryConnector() override {}
+
+ void ConnectToService(ApplicationConnection* application_connection,
+ const std::string& interface_name,
+ ScopedMessagePipeHandle client_handle) override {
+ factory_->Create(application_connection,
+ MakeRequest<Interface>(std::move(client_handle)));
+ }
+
+ private:
+ InterfaceFactory<Interface>* factory_;
+ MOJO_DISALLOW_COPY_AND_ASSIGN(InterfaceFactoryConnector);
+};
+
+} // namespace internal
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_LIB_INTERFACE_FACTORY_CONNECTOR_H_
diff --git a/mojo/shell/public/cpp/lib/service_connector_registry.cc b/mojo/shell/public/cpp/lib/service_connector_registry.cc
new file mode 100644
index 0000000..edc91e0
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/service_connector_registry.cc
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/shell/public/cpp/lib/service_connector_registry.h"
+
+#include <utility>
+
+#include "mojo/shell/public/cpp/service_connector.h"
+
+namespace mojo {
+namespace internal {
+
+ServiceConnectorRegistry::ServiceConnectorRegistry()
+ : service_connector_(nullptr) {
+}
+
+ServiceConnectorRegistry::~ServiceConnectorRegistry() {
+ for (NameToServiceConnectorMap::iterator i =
+ name_to_service_connector_.begin();
+ i != name_to_service_connector_.end(); ++i) {
+ delete i->second;
+ }
+ name_to_service_connector_.clear();
+}
+
+void ServiceConnectorRegistry::SetServiceConnectorForName(
+ ServiceConnector* service_connector,
+ const std::string& interface_name) {
+ RemoveServiceConnectorForName(interface_name);
+ name_to_service_connector_[interface_name] = service_connector;
+}
+
+void ServiceConnectorRegistry::RemoveServiceConnectorForName(
+ const std::string& interface_name) {
+ NameToServiceConnectorMap::iterator it =
+ name_to_service_connector_.find(interface_name);
+ if (it == name_to_service_connector_.end())
+ return;
+ delete it->second;
+ name_to_service_connector_.erase(it);
+}
+
+void ServiceConnectorRegistry::ConnectToService(
+ ApplicationConnection* application_connection,
+ const std::string& interface_name,
+ ScopedMessagePipeHandle client_handle) {
+ auto iter = name_to_service_connector_.find(interface_name);
+ if (iter != name_to_service_connector_.end()) {
+ iter->second->ConnectToService(application_connection, interface_name,
+ std::move(client_handle));
+ return;
+ }
+ if (service_connector_) {
+ service_connector_->ConnectToService(application_connection, interface_name,
+ std::move(client_handle));
+ }
+}
+
+} // namespace internal
+} // namespace mojo
diff --git a/mojo/shell/public/cpp/lib/service_connector_registry.h b/mojo/shell/public/cpp/lib/service_connector_registry.h
new file mode 100644
index 0000000..9475436
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/service_connector_registry.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 MOJO_SHELL_PUBLIC_CPP_LIB_SERVICE_CONNECTOR_REGISTRY_H_
+#define MOJO_SHELL_PUBLIC_CPP_LIB_SERVICE_CONNECTOR_REGISTRY_H_
+
+#include <map>
+#include <string>
+
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace mojo {
+
+class ApplicationConnection;
+class ServiceConnector;
+
+namespace internal {
+
+// ServiceConnectorRegistry maintains a default ServiceConnector as well as at
+// most one ServiceConnector per interface name. When ConnectToService() is
+// invoked the ServiceConnector registered by name is given the request. If
+// a ServiceConnector has not been registered by name than the default
+// ServiceConnector is given the request.
+class ServiceConnectorRegistry {
+ public:
+ ServiceConnectorRegistry();
+ ~ServiceConnectorRegistry();
+
+ // Sets the default ServiceConnector. ServiceConnectorRegistry does *not*
+ // take ownership of |service_connector|.
+ void set_service_connector(ServiceConnector* service_connector) {
+ service_connector_ = service_connector;
+ }
+
+ // Returns true if non ServiceConnectors have been registered by name.
+ bool empty() const { return name_to_service_connector_.empty(); }
+
+ // Sets a ServiceConnector by name. This deletes the existing ServiceConnector
+ // and takes ownership of |service_connector|.
+ void SetServiceConnectorForName(ServiceConnector* service_connector,
+ const std::string& interface_name);
+ void RemoveServiceConnectorForName(const std::string& interface_name);
+
+ void ConnectToService(ApplicationConnection* application_connection,
+ const std::string& interface_name,
+ ScopedMessagePipeHandle client_handle);
+
+ private:
+ using NameToServiceConnectorMap = std::map<std::string, ServiceConnector*>;
+
+ ServiceConnector* service_connector_;
+
+ NameToServiceConnectorMap name_to_service_connector_;
+
+ MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceConnectorRegistry);
+};
+
+} // namespace internal
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_LIB_SERVICE_CONNECTOR_REGISTRY_H_
diff --git a/mojo/shell/public/cpp/lib/service_provider_impl.cc b/mojo/shell/public/cpp/lib/service_provider_impl.cc
new file mode 100644
index 0000000..4a411a2
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/service_provider_impl.cc
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/shell/public/cpp/service_connector.h"
+#include "mojo/shell/public/cpp/service_provider_impl.h"
+
+namespace mojo {
+
+ServiceProviderImpl::ServiceProviderImpl() : binding_(this) {
+}
+
+ServiceProviderImpl::ServiceProviderImpl(
+ InterfaceRequest<ServiceProvider> request)
+ : binding_(this, std::move(request)) {}
+
+ServiceProviderImpl::~ServiceProviderImpl() {
+}
+
+void ServiceProviderImpl::Bind(InterfaceRequest<ServiceProvider> request) {
+ binding_.Bind(std::move(request));
+}
+
+void ServiceProviderImpl::ConnectToService(
+ const String& service_name,
+ ScopedMessagePipeHandle client_handle) {
+ // TODO(beng): perhaps take app connection thru ctor so that we can pass
+ // ApplicationConnection through?
+ service_connector_registry_.ConnectToService(nullptr, service_name,
+ std::move(client_handle));
+}
+
+void ServiceProviderImpl::SetServiceConnectorForName(
+ ServiceConnector* service_connector,
+ const std::string& interface_name) {
+ service_connector_registry_.SetServiceConnectorForName(service_connector,
+ interface_name);
+}
+
+} // namespace mojo
diff --git a/mojo/shell/public/cpp/lib/service_registry.cc b/mojo/shell/public/cpp/lib/service_registry.cc
new file mode 100644
index 0000000..09f71de
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/service_registry.cc
@@ -0,0 +1,138 @@
+// 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/shell/public/cpp/lib/service_registry.h"
+
+#include <stdint.h>
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "mojo/shell/public/cpp/application_connection.h"
+#include "mojo/shell/public/cpp/service_connector.h"
+
+namespace mojo {
+namespace internal {
+
+ServiceRegistry::ServiceRegistry(
+ const std::string& connection_url,
+ const std::string& remote_url,
+ ServiceProviderPtr remote_services,
+ InterfaceRequest<ServiceProvider> local_services,
+ const std::set<std::string>& allowed_interfaces)
+ : connection_url_(connection_url),
+ remote_url_(remote_url),
+ local_binding_(this),
+ remote_service_provider_(std::move(remote_services)),
+ allowed_interfaces_(allowed_interfaces),
+ allow_all_interfaces_(allowed_interfaces_.size() == 1 &&
+ allowed_interfaces_.count("*") == 1),
+ content_handler_id_(0u),
+ is_content_handler_id_valid_(false),
+ weak_factory_(this) {
+ if (local_services.is_pending())
+ local_binding_.Bind(std::move(local_services));
+}
+
+ServiceRegistry::ServiceRegistry()
+ : local_binding_(this),
+ allow_all_interfaces_(true),
+ weak_factory_(this) {
+}
+
+ServiceRegistry::~ServiceRegistry() {
+}
+
+Shell::ConnectToApplicationCallback
+ServiceRegistry::GetConnectToApplicationCallback() {
+ return base::Bind(&ServiceRegistry::OnGotContentHandlerID,
+ weak_factory_.GetWeakPtr());
+}
+
+void ServiceRegistry::SetServiceConnector(ServiceConnector* connector) {
+ service_connector_registry_.set_service_connector(connector);
+}
+
+bool ServiceRegistry::SetServiceConnectorForName(
+ ServiceConnector* service_connector,
+ const std::string& interface_name) {
+ if (allow_all_interfaces_ ||
+ allowed_interfaces_.count(interface_name)) {
+ service_connector_registry_.SetServiceConnectorForName(service_connector,
+ interface_name);
+ return true;
+ }
+ LOG(WARNING) << "CapabilityFilter prevented connection to interface: "
+ << interface_name << " connection_url:" << connection_url_
+ << " remote_url:" << remote_url_;
+ return false;
+}
+
+ServiceProvider* ServiceRegistry::GetLocalServiceProvider() {
+ return this;
+}
+
+void ServiceRegistry::SetRemoteServiceProviderConnectionErrorHandler(
+ const Closure& handler) {
+ remote_service_provider_.set_connection_error_handler(handler);
+}
+
+bool ServiceRegistry::GetContentHandlerID(uint32_t* content_handler_id) {
+ if (!is_content_handler_id_valid_)
+ return false;
+
+ *content_handler_id = content_handler_id_;
+ return true;
+}
+
+void ServiceRegistry::AddContentHandlerIDCallback(const Closure& callback) {
+ if (is_content_handler_id_valid_) {
+ callback.Run();
+ return;
+ }
+ content_handler_id_callbacks_.push_back(callback);
+}
+
+base::WeakPtr<ApplicationConnection> ServiceRegistry::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
+void ServiceRegistry::RemoveServiceConnectorForName(
+ const std::string& interface_name) {
+ service_connector_registry_.RemoveServiceConnectorForName(interface_name);
+ if (service_connector_registry_.empty())
+ remote_service_provider_.reset();
+}
+
+const std::string& ServiceRegistry::GetConnectionURL() {
+ return connection_url_;
+}
+
+const std::string& ServiceRegistry::GetRemoteApplicationURL() {
+ return remote_url_;
+}
+
+ServiceProvider* ServiceRegistry::GetServiceProvider() {
+ return remote_service_provider_.get();
+}
+
+void ServiceRegistry::OnGotContentHandlerID(uint32_t content_handler_id) {
+ DCHECK(!is_content_handler_id_valid_);
+ is_content_handler_id_valid_ = true;
+ content_handler_id_ = content_handler_id;
+ std::vector<Closure> callbacks;
+ callbacks.swap(content_handler_id_callbacks_);
+ for (auto callback : callbacks)
+ callback.Run();
+}
+
+void ServiceRegistry::ConnectToService(const mojo::String& service_name,
+ ScopedMessagePipeHandle client_handle) {
+ service_connector_registry_.ConnectToService(this, service_name,
+ std::move(client_handle));
+}
+
+} // namespace internal
+} // namespace mojo
diff --git a/mojo/shell/public/cpp/lib/service_registry.h b/mojo/shell/public/cpp/lib/service_registry.h
new file mode 100644
index 0000000..1c2abc9
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/service_registry.h
@@ -0,0 +1,83 @@
+// 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_SHELL_PUBLIC_CPP_LIB_SERVICE_REGISTRY_H_
+#define MOJO_SHELL_PUBLIC_CPP_LIB_SERVICE_REGISTRY_H_
+
+#include <stdint.h>
+
+#include <set>
+#include <string>
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/shell/public/cpp/application_connection.h"
+#include "mojo/shell/public/cpp/lib/service_connector_registry.h"
+#include "mojo/shell/public/interfaces/service_provider.mojom.h"
+#include "mojo/shell/public/interfaces/shell.mojom.h"
+
+namespace mojo {
+namespace internal {
+
+// A ServiceRegistry represents each half of a connection between two
+// applications, allowing customization of which services are published to the
+// other.
+class ServiceRegistry : public ServiceProvider, public ApplicationConnection {
+ public:
+ ServiceRegistry();
+ // |allowed_interfaces| are the set of interfaces that the shell has allowed
+ // an application to expose to another application. If this set contains only
+ // the string value "*" all interfaces may be exposed.
+ ServiceRegistry(const std::string& connection_url,
+ const std::string& remote_url,
+ ServiceProviderPtr remote_services,
+ InterfaceRequest<ServiceProvider> local_services,
+ const std::set<std::string>& allowed_interfaces);
+ ~ServiceRegistry() override;
+
+ Shell::ConnectToApplicationCallback GetConnectToApplicationCallback();
+
+ // ApplicationConnection overrides.
+ void SetServiceConnector(ServiceConnector* service_connector) override;
+ bool SetServiceConnectorForName(ServiceConnector* service_connector,
+ const std::string& interface_name) override;
+ const std::string& GetConnectionURL() override;
+ const std::string& GetRemoteApplicationURL() override;
+ ServiceProvider* GetServiceProvider() override;
+ ServiceProvider* GetLocalServiceProvider() override;
+ void SetRemoteServiceProviderConnectionErrorHandler(
+ const Closure& handler) override;
+ bool GetContentHandlerID(uint32_t* target_id) override;
+ void AddContentHandlerIDCallback(const Closure& callback) override;
+ base::WeakPtr<ApplicationConnection> GetWeakPtr() override;
+
+ void RemoveServiceConnectorForName(const std::string& interface_name);
+
+ private:
+ void OnGotContentHandlerID(uint32_t content_handler_id);
+
+ // ServiceProvider method.
+ void ConnectToService(const mojo::String& service_name,
+ ScopedMessagePipeHandle client_handle) override;
+
+ const std::string connection_url_;
+ const std::string remote_url_;
+ Binding<ServiceProvider> local_binding_;
+ ServiceProviderPtr remote_service_provider_;
+ ServiceConnectorRegistry service_connector_registry_;
+ const std::set<std::string> allowed_interfaces_;
+ const bool allow_all_interfaces_;
+ // The id of the content_handler is only available once the callback from
+ // establishing the connection is made.
+ uint32_t content_handler_id_;
+ bool is_content_handler_id_valid_;
+ std::vector<Closure> content_handler_id_callbacks_;
+ base::WeakPtrFactory<ServiceRegistry> weak_factory_;
+
+ MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceRegistry);
+};
+
+} // namespace internal
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_LIB_SERVICE_REGISTRY_H_
diff --git a/mojo/shell/public/cpp/service_connector.h b/mojo/shell/public/cpp/service_connector.h
new file mode 100644
index 0000000..8856e3f
--- /dev/null
+++ b/mojo/shell/public/cpp/service_connector.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_SHELL_PUBLIC_CPP_SERVICE_CONNECTOR_H_
+#define MOJO_SHELL_PUBLIC_CPP_SERVICE_CONNECTOR_H_
+
+#include <string>
+
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace mojo {
+
+class ApplicationConnection;
+
+class ServiceConnector {
+ public:
+ virtual ~ServiceConnector() {}
+
+ // Asks the ServiceConnector to connect to the specified service. If the
+ // ServiceConnector connects to the service it should take ownership of
+ // the handle in |handle|.
+ virtual void ConnectToService(ApplicationConnection* application_connection,
+ const std::string& interface_name,
+ ScopedMessagePipeHandle handle) = 0;
+};
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_SERVICE_CONNECTOR_H_
diff --git a/mojo/shell/public/cpp/service_provider_impl.h b/mojo/shell/public/cpp/service_provider_impl.h
new file mode 100644
index 0000000..2d5ed75
--- /dev/null
+++ b/mojo/shell/public/cpp/service_provider_impl.h
@@ -0,0 +1,50 @@
+// 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_SHELL_PUBLIC_CPP_SERVICE_PROVIDER_IMPL_H_
+#define MOJO_SHELL_PUBLIC_CPP_SERVICE_PROVIDER_IMPL_H_
+
+#include <string>
+
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/shell/public/cpp/lib/interface_factory_connector.h"
+#include "mojo/shell/public/cpp/lib/service_connector_registry.h"
+#include "mojo/shell/public/interfaces/service_provider.mojom.h"
+
+namespace mojo {
+
+// Implements a registry that can be used to expose services to another app.
+class ServiceProviderImpl : public ServiceProvider {
+ public:
+ ServiceProviderImpl();
+ explicit ServiceProviderImpl(InterfaceRequest<ServiceProvider> request);
+ ~ServiceProviderImpl() override;
+
+ void Bind(InterfaceRequest<ServiceProvider> request);
+
+ template <typename Interface>
+ void AddService(InterfaceFactory<Interface>* factory) {
+ SetServiceConnectorForName(
+ new internal::InterfaceFactoryConnector<Interface>(factory),
+ Interface::Name_);
+ }
+
+ private:
+ // Overridden from ServiceProvider:
+ void ConnectToService(const String& service_name,
+ ScopedMessagePipeHandle client_handle) override;
+
+ void SetServiceConnectorForName(ServiceConnector* service_connector,
+ const std::string& interface_name);
+
+ StrongBinding<ServiceProvider> binding_;
+
+ internal::ServiceConnectorRegistry service_connector_registry_;
+
+ MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceProviderImpl);
+};
+
+} // namespace mojo
+
+#endif // MOJO_SHELL_PUBLIC_CPP_SERVICE_PROVIDER_IMPL_H_
diff --git a/mojo/shell/public/cpp/tests/BUILD.gn b/mojo/shell/public/cpp/tests/BUILD.gn
new file mode 100644
index 0000000..51da838
--- /dev/null
+++ b/mojo/shell/public/cpp/tests/BUILD.gn
@@ -0,0 +1,18 @@
+# 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("//testing/test.gni")
+
+test("mojo_public_application_unittests") {
+ sources = [
+ "service_registry_unittest.cc",
+ ]
+
+ deps = [
+ "//base",
+ "//mojo/shell/public/cpp",
+ "//testing/gtest",
+ "//third_party/mojo/src/mojo/edk/test:run_all_unittests",
+ ]
+}
diff --git a/mojo/shell/public/cpp/tests/service_registry_unittest.cc b/mojo/shell/public/cpp/tests/service_registry_unittest.cc
new file mode 100644
index 0000000..349e9aa
--- /dev/null
+++ b/mojo/shell/public/cpp/tests/service_registry_unittest.cc
@@ -0,0 +1,72 @@
+// 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/shell/public/cpp/lib/service_registry.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "mojo/shell/public/cpp/service_connector.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace internal {
+namespace {
+
+class TestConnector : public ServiceConnector {
+ public:
+ explicit TestConnector(int* delete_count) : delete_count_(delete_count) {}
+ ~TestConnector() override { (*delete_count_)++; }
+ void ConnectToService(ApplicationConnection* application_connection,
+ const std::string& interface_name,
+ ScopedMessagePipeHandle client_handle) override {}
+
+ private:
+ int* delete_count_;
+};
+
+TEST(ServiceRegistryTest, Ownership) {
+ int delete_count = 0;
+
+ // Destruction.
+ {
+ ServiceRegistry registry;
+ registry.SetServiceConnectorForName(new TestConnector(&delete_count),
+ "TC1");
+ }
+ EXPECT_EQ(1, delete_count);
+
+ // Removal.
+ {
+ scoped_ptr<ServiceRegistry> registry(new ServiceRegistry);
+ ServiceConnector* c = new TestConnector(&delete_count);
+ registry->SetServiceConnectorForName(c, "TC1");
+ registry->RemoveServiceConnectorForName("TC1");
+ registry.reset();
+ EXPECT_EQ(2, delete_count);
+ }
+
+ // Multiple.
+ {
+ ServiceRegistry registry;
+ registry.SetServiceConnectorForName(new TestConnector(&delete_count),
+ "TC1");
+ registry.SetServiceConnectorForName(new TestConnector(&delete_count),
+ "TC2");
+ }
+ EXPECT_EQ(4, delete_count);
+
+ // Re-addition.
+ {
+ ServiceRegistry registry;
+ registry.SetServiceConnectorForName(new TestConnector(&delete_count),
+ "TC1");
+ registry.SetServiceConnectorForName(new TestConnector(&delete_count),
+ "TC1");
+ EXPECT_EQ(5, delete_count);
+ }
+ EXPECT_EQ(6, delete_count);
+}
+
+} // namespace
+} // namespace internal
+} // namespace mojo
diff --git a/mojo/shell/public/interfaces/BUILD.gn b/mojo/shell/public/interfaces/BUILD.gn
new file mode 100644
index 0000000..1aa7fc5
--- /dev/null
+++ b/mojo/shell/public/interfaces/BUILD.gn
@@ -0,0 +1,22 @@
+# 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/mojo_base.gyp:mojo_application_bindings
+mojom("interfaces") {
+ sources = [
+ "application.mojom",
+ "application_manager.mojom",
+ "content_handler.mojom",
+ "service_provider.mojom",
+ "shell.mojom",
+ ]
+
+ import_dirs = [ "//mojo/services" ]
+
+ deps = [
+ "//mojo/services/network/public/interfaces",
+ ]
+}
diff --git a/mojo/shell/public/interfaces/application.mojom b/mojo/shell/public/interfaces/application.mojom
new file mode 100644
index 0000000..f0a8724
--- /dev/null
+++ b/mojo/shell/public/interfaces/application.mojom
@@ -0,0 +1,70 @@
+// 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;
+
+import "mojo/shell/public/interfaces/service_provider.mojom";
+import "mojo/shell/public/interfaces/shell.mojom";
+
+// This is the primary interface implemented by every Mojo application. It
+// allows the application to receive its startup arguments from the shell, and
+// to be notified of events that occur during its execution.
+//
+// TODO(aa): It would be good to reorder the parameters once we have interface
+// versioning.
+interface Application {
+ // Initializes the application with the specified arguments. This method is
+ // guaranteed to be called before any other method is called, and will only be
+ // called once.
+ //
+ // The |url| parameter is the identity of the application as far as the shell
+ // is concerned. This will be the URL the application was found at, after all
+ // mappings, resolution, and redirects. And it will not include the
+ // querystring, since the querystring is not part of an application's
+ // identity.
+ Initialize(Shell shell, string url);
+
+ // Called when another application (identified by |requestor_url|) attempts to
+ // open a connection to this application.
+ //
+ // If the other application wants to request services from this application,
+ // it will have passed a valid interface request through the |services|
+ // parameter (i.e. one containing a valid message pipe endpoint). This
+ // application may then bind an implementation of |ServiceProvider| to that
+ // request in order to make services available to the other application.
+ //
+ // If the other application wants to offer services to this application, it
+ // will have passed a bound interface through the |exposed_services|
+ // parameter. This application may then request services through that
+ // interface.
+ //
+ // It is possible that both parameters will be valid/bound if the other
+ // application wants to both request services from and offer services to this
+ // application.
+ //
+ // This application is free to ignore the |services| or |exposed_services|
+ // parameters if it does not wish to offer or request services.
+ //
+ // |allowed_interfaces| is a set of interface names that the shell has
+ // determined can be exposed by this application to the connecting
+ // application. When this parameter is empty, this application should expose
+ // no services to the connecting application. When this parameter contains
+ // only the single string value "*" the application may expose all of its
+ // services to the connecting application.
+ //
+ // |resolved_url| is the URL that was requested to create this connection,
+ // after all mappings, resolutions, and redirects. This will include any
+ // querystring that was part of the request.
+ //
+ AcceptConnection(string requestor_url,
+ ServiceProvider&? services,
+ ServiceProvider? exposed_services,
+ array<string> allowed_interfaces,
+ string resolved_url);
+
+ // Called by the shell in response to calling Shell's QuitApplication. The
+ // application should run the callback with true if shutdown can proceed.
+ // See Shell::QuitApplication for details about shutdown workflow.
+ OnQuitRequested() => (bool can_quit);
+};
diff --git a/mojo/shell/public/interfaces/application_manager.mojom b/mojo/shell/public/interfaces/application_manager.mojom
new file mode 100644
index 0000000..02d059a
--- /dev/null
+++ b/mojo/shell/public/interfaces/application_manager.mojom
@@ -0,0 +1,67 @@
+// 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.
+
+module mojo.shell.mojom;
+
+import "mojo/shell/public/interfaces/shell.mojom";
+
+struct ApplicationInfo {
+ int32 id;
+ string url;
+ string qualifier;
+ uint32 pid;
+};
+
+// Implemented by an application that wishes to be informed when the list of
+// running applications changes.
+interface ApplicationManagerListener {
+ // Called once when the listener is added via
+ // ApplicationManager::AddListener() to provide the initial list of running
+ // applications that the listener observes changes against.
+ SetRunningApplications(array<ApplicationInfo> applications);
+
+ // Called when the application manager has started tracking an application.
+ // This happens when the application manager first handles a request to launch
+ // the application, and before any process or content handler is created for
+ // it.
+ ApplicationInstanceCreated(ApplicationInfo application);
+
+ // Called when the application manager has stopped tracking an application.
+ // (i.e. when it has ended/quit).
+ ApplicationInstanceDestroyed(int32 id);
+
+ // Called when a pid is available for the application. This could be because a
+ // process was created by the runner for it, or because an existing content
+ // handler process was assigned.
+ ApplicationPIDAvailable(int32 id, uint32 pid);
+};
+
+// Implemented by an object in the application manager associated with a
+// specific instance. Tells it the PID for a process launched by the client.
+// This interface is only available to callers of ApplicationManager::
+// CreateInstanceForHandle().
+interface PIDReceiver {
+ SetPID(uint32 pid);
+};
+
+interface ApplicationManager {
+ // Instructs the ApplicationManager to create an instance for an existing
+ // process at the other end of |channel|, and perform applicable
+ // initialization. This assumes the target process will bind the other end of
+ // channel to an implementation of ChildController and bind an Application
+ // request there.
+ CreateInstanceForHandle(handle channel,
+ string url,
+ mojo.CapabilityFilter filter,
+ PIDReceiver& pid_receiver);
+
+ // Called by a child process every time it launches a process. This is needed
+ // so that the ChildBroker class in the grandchild process can talk to the one
+ // global BrokerState in the parent mojo_runner process.
+ RegisterProcessWithBroker(uint32 pid,
+ handle pipe);
+
+ // The listener is removed when the pipe is closed.
+ AddListener(ApplicationManagerListener listener);
+};
diff --git a/mojo/shell/public/interfaces/content_handler.mojom b/mojo/shell/public/interfaces/content_handler.mojom
new file mode 100644
index 0000000..5fdb826
--- /dev/null
+++ b/mojo/shell/public/interfaces/content_handler.mojom
@@ -0,0 +1,20 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module mojo;
+
+import "mojo/shell/public/interfaces/application.mojom";
+import "network/public/interfaces/url_loader.mojom";
+
+// Interface implemented by content handlers. To avoid race conditions with
+// dropped requests, the implementation should keep a reference to the lifetime
+// of the app (by holding on to AppRefCount). Each application started by
+// StartApplication should call the callback given by that method on
+// destruction. When the owner in the shell notices this, it will destroy the
+// interface pointer, which should cause the strongly-bound ContentHandler
+// implementation to self destruct and release the app reference.
+interface ContentHandler {
+ // The callback should be called when the application is destructed.
+ StartApplication(Application& application, URLResponse response) => ();
+};
diff --git a/mojo/shell/public/interfaces/service_provider.mojom b/mojo/shell/public/interfaces/service_provider.mojom
new file mode 100644
index 0000000..8c81879
--- /dev/null
+++ b/mojo/shell/public/interfaces/service_provider.mojom
@@ -0,0 +1,17 @@
+// 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;
+
+// An interface through which a client may request services from a host.
+// Instances of this interface are created within the context of an
+// already-identified client and host pair, so there is no need to explicitly
+// identify the client or host in the methods below.
+interface ServiceProvider {
+ // Asks the host to provide the service identified by |interface_name| through
+ // the message |pipe| endpoint supplied by the caller. If the host is not
+ // willing or able to provide the requested service, it should close the
+ // |pipe|.
+ ConnectToService(string interface_name, handle<message_pipe> pipe);
+};
diff --git a/mojo/shell/public/interfaces/shell.mojom b/mojo/shell/public/interfaces/shell.mojom
new file mode 100644
index 0000000..b70b9fe
--- /dev/null
+++ b/mojo/shell/public/interfaces/shell.mojom
@@ -0,0 +1,79 @@
+// 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;
+
+import "mojo/shell/public/interfaces/service_provider.mojom";
+import "network/public/interfaces/url_loader.mojom";
+
+// Specifies a whitelist of applications and services an application can connect
+// to. Connections to applications not explicitly specified here as a key are
+// rejected. Connections to services not specified in an application's allowed
+// interfaces value are not made.
+// A "*" value as the only key in an otherwise empty map means the application
+// may connect to any other application.
+// A "*" value as the only string in an otherwise empty array of interface names
+// means the application may connect to any service in that application.
+// An empty interface name array means the application may not connect to any
+// services exposed by the application it is connecting to.
+struct CapabilityFilter {
+ map<string, array<string>> filter;
+};
+
+// An interface through which a Mojo application may communicate with the Mojo
+// system and request connections to other applications.
+interface Shell {
+ // Used to indicate the app was not launched by a content handler.
+ const uint32 kInvalidContentHandlerID = 0;
+
+ // Establishes a connection with another application ("target application")
+ // (located at |request->url|) through which the calling application and the
+ // target application may request services from one another.
+ // |application_url| is a URLRequest in case this is called for an HTTP
+ // navigation, in which case HTTP specific information like POST data,
+ // referrer header etc... needed.
+ //
+ // If the calling application would like to request services from the target
+ // application, it should pass a valid interface request in the |services|
+ // parameter (i.e. one containing a valid message pipe endpoint). If the
+ // target application does not wish to offer services, it may either not bind
+ // an implementation to the interface request, or else bind an implementation
+ // that will reject some or all service requests.
+ //
+ // If the calling application would like to offer services to the target
+ // application, it should pass a bound interface through the
+ // |exposed_services| parameter. The target application may then request
+ // services through that interface.
+ //
+ // At least one of |services| or |exposed_services| should be valid/bound in
+ // the call.
+ //
+ // If the |application_url| does not contain a domain, but is of the form
+ // "mojo:{service}", it is up to the Mojo shell to select an appropriate
+ // application for the service. Currently, the shell does this based on the
+ // value of its --origin flag.
+ //
+ // |filter| is a whitelist of application URLs and services that the target
+ // application is permitted to connect to. See documentation for
+ // CapabilityFilter above.
+ //
+ // If the connection to |application_url| involves a content handler, then
+ // |content_handler_id| is the id of the deepest content handler used to
+ // establish the connection to |application_url|. If no content handler is
+ // used |content_handler_id| is kInvalidContentHandlerID.
+ // TODO(beng): determine if we need to expose the target application id also.
+ ConnectToApplication(URLRequest application_url,
+ ServiceProvider&? services,
+ ServiceProvider? exposed_services,
+ CapabilityFilter filter) => (uint32 content_handler_id);
+
+ // When there are no more instantiated services in an application, it should
+ // start its shutdown process by calling this method. Additionally, it should
+ // keep track of any new service requests that come in. The shell will then
+ // call Application::OnQuitRequested and start queueing new service requests.
+ // If the application didn't get any new service requests in the meantime, it
+ // should call the callback with a true value. Otherwise it should call it
+ // with false.
+ QuitApplication();
+};
diff --git a/mojo/shell/public/java/BUILD.gn b/mojo/shell/public/java/BUILD.gn
new file mode 100644
index 0000000..a89d0fc
--- /dev/null
+++ b/mojo/shell/public/java/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+android_library("application") {
+ java_files = [
+ "src/org/chromium/mojo/application/ApplicationConnection.java",
+ "src/org/chromium/mojo/application/ApplicationDelegate.java",
+ "src/org/chromium/mojo/application/ApplicationImpl.java",
+ "src/org/chromium/mojo/application/ApplicationRunner.java",
+ "src/org/chromium/mojo/application/ServiceFactoryBinder.java",
+ "src/org/chromium/mojo/application/ShellHelper.java",
+ ]
+ deps = [
+ "//mojo/public/java:bindings",
+ "//mojo/public/java:system",
+ "//mojo/shell/public/interfaces:interfaces_java",
+ ]
+}
diff --git a/mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationConnection.java b/mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationConnection.java
new file mode 100644
index 0000000..6b0e548
--- /dev/null
+++ b/mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationConnection.java
@@ -0,0 +1,107 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.mojo.application;
+
+import org.chromium.mojo.bindings.Interface;
+import org.chromium.mojo.system.MessagePipeHandle;
+import org.chromium.mojo.system.MojoException;
+import org.chromium.mojom.mojo.ServiceProvider;
+
+import java.io.Closeable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a connection to another application.
+ */
+public class ApplicationConnection implements Closeable {
+ private final String mConnectionUrl;
+ private final ServiceProvider mExposedServices;
+ private final String mRequestorUrl;
+ private final ServiceProviderImpl mServiceProviderImpl;
+
+ /**
+ * @param requestorUrl URL of the application requesting this connection.
+ * @param exposedServices ServiceProvider for services exposed by the remote application.
+ */
+ public ApplicationConnection(
+ String requestorUrl, ServiceProvider exposedServices, String connectionUrl) {
+ mRequestorUrl = requestorUrl;
+ mExposedServices = exposedServices;
+ mConnectionUrl = connectionUrl;
+ mServiceProviderImpl = new ServiceProviderImpl();
+ }
+
+ /**
+ * @return URL of the application requesting this connection.
+ */
+ public String getRequestorUrl() {
+ return mRequestorUrl;
+ }
+
+ /**
+ * @return URL that was used by the source application to establish this connection.
+ */
+ public String connectionUrl() {
+ return mConnectionUrl;
+ }
+
+ /**
+ * @return ServiceProvider for services exposed by the remote application.
+ */
+ public ServiceProvider getRemoteServiceProvider() {
+ return mExposedServices;
+ }
+
+ /**
+ * Add a new service for this application.
+ *
+ * @param binder Handle to a ServiceFactoryBinder which contains a service implementation.
+ */
+ public void addService(ServiceFactoryBinder<? extends Interface> binder) {
+ mServiceProviderImpl.addService(binder);
+ }
+
+ /**
+ * @return ServiceProvider for this application.
+ */
+ public ServiceProvider getLocalServiceProvider() {
+ return mServiceProviderImpl;
+ }
+
+ @Override
+ public void close() {
+ mServiceProviderImpl.close();
+ if (mExposedServices != null) {
+ mExposedServices.close();
+ }
+ }
+}
+
+class ServiceProviderImpl implements ServiceProvider {
+ private final Map<String, ServiceFactoryBinder<? extends Interface>> mNameToServiceMap =
+ new HashMap<String, ServiceFactoryBinder<? extends Interface>>();
+
+ ServiceProviderImpl() {}
+
+ public void addService(ServiceFactoryBinder<? extends Interface> binder) {
+ mNameToServiceMap.put(binder.getInterfaceName(), binder);
+ }
+
+ @Override
+ public void connectToService(String interfaceName, MessagePipeHandle pipe) {
+ if (mNameToServiceMap.containsKey(interfaceName)) {
+ mNameToServiceMap.get(interfaceName).bindNewInstanceToMessagePipe(pipe);
+ } else {
+ pipe.close();
+ }
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public void onConnectionError(MojoException e) {}
+} \ No newline at end of file
diff --git a/mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationDelegate.java b/mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationDelegate.java
new file mode 100644
index 0000000..72b1c62
--- /dev/null
+++ b/mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationDelegate.java
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.mojo.application;
+
+import org.chromium.mojom.mojo.Shell;
+
+/**
+ * Applications should implement this interface to control various behaviors of Mojo application
+ * interface.
+ */
+public interface ApplicationDelegate {
+ /**
+ * Called exactly once before any other method.
+ *
+ * @param shell A handle to the shell interface.
+ * @param args Arguments used for this application.
+ * @param url URL of this application.
+ */
+ public void initialize(Shell shell, String[] args, String url);
+
+ /**
+ * This method is used to configure what services a connection supports when being connected to.
+ * Return false to reject the connection entirely.
+ *
+ * @param connection A handle to the connection.
+ * @return If this application accepts any incoming connection.
+ */
+ public boolean configureIncomingConnection(ApplicationConnection connection);
+
+ /**
+ * Called before exiting. After returning from this call, the delegate cannot expect RunLoop to
+ * still be running.
+ */
+ public void quit();
+}
diff --git a/mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationImpl.java b/mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationImpl.java
new file mode 100644
index 0000000..7768b8d
--- /dev/null
+++ b/mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationImpl.java
@@ -0,0 +1,71 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.mojo.application;
+
+import org.chromium.mojo.bindings.InterfaceRequest;
+import org.chromium.mojo.system.Core;
+import org.chromium.mojo.system.MessagePipeHandle;
+import org.chromium.mojo.system.MojoException;
+import org.chromium.mojom.mojo.Application;
+import org.chromium.mojom.mojo.ServiceProvider;
+import org.chromium.mojom.mojo.Shell;
+
+import java.util.ArrayList;
+
+/**
+ * Utility class for communicating with the Shell, and provide Services to clients.
+ */
+class ApplicationImpl implements Application {
+ private final ApplicationDelegate mApplicationDelegate;
+ private final ArrayList<ApplicationConnection> mIncomingConnections =
+ new ArrayList<ApplicationConnection>();
+ private final Core mCore;
+ private Shell mShell;
+
+ public ApplicationImpl(
+ ApplicationDelegate delegate, Core core, MessagePipeHandle applicationRequest) {
+ mApplicationDelegate = delegate;
+ mCore = core;
+ ApplicationImpl.MANAGER.bind(this, applicationRequest);
+ }
+
+ @Override
+ public void initialize(Shell shell, String[] args, String url) {
+ mShell = shell;
+ mApplicationDelegate.initialize(shell, args, url);
+ }
+
+ @Override
+ public void acceptConnection(String requestorUrl, InterfaceRequest<ServiceProvider> services,
+ ServiceProvider exposedServices, String connectionUrl) {
+ ApplicationConnection connection =
+ new ApplicationConnection(requestorUrl, exposedServices, connectionUrl);
+ if (services != null && mApplicationDelegate.configureIncomingConnection(connection)) {
+ ServiceProvider.MANAGER.bind(connection.getLocalServiceProvider(), services);
+ mIncomingConnections.add(connection);
+ } else {
+ connection.close();
+ }
+ }
+
+ @Override
+ public void requestQuit() {
+ mApplicationDelegate.quit();
+ for (ApplicationConnection connection : mIncomingConnections) {
+ connection.close();
+ }
+ mCore.getCurrentRunLoop().quit();
+ }
+
+ @Override
+ public void close() {
+ if (mShell != null) {
+ mShell.close();
+ }
+ }
+
+ @Override
+ public void onConnectionError(MojoException e) {}
+}
diff --git a/mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationRunner.java b/mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationRunner.java
new file mode 100644
index 0000000..1a903b4
--- /dev/null
+++ b/mojo/shell/public/java/src/org/chromium/mojo/application/ApplicationRunner.java
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.mojo.application;
+
+import org.chromium.mojo.system.Core;
+import org.chromium.mojo.system.MessagePipeHandle;
+import org.chromium.mojo.system.RunLoop;
+
+/**
+ * A utility for running an Application.
+ *
+ */
+public class ApplicationRunner {
+ /**
+ * Runs the delegate in a RunLoop.
+ *
+ * @param delegate Application specific functionality.
+ * @param core Core mojo interface.
+ * @param applicationRequest Handle for the application request.
+ */
+ public static void run(
+ ApplicationDelegate delegate, Core core, MessagePipeHandle applicationRequest) {
+ try (RunLoop runLoop = core.createDefaultRunLoop()) {
+ try (ApplicationImpl application =
+ new ApplicationImpl(delegate, core, applicationRequest)) {
+ runLoop.run();
+ }
+ }
+ }
+}
diff --git a/mojo/shell/public/java/src/org/chromium/mojo/application/ServiceFactoryBinder.java b/mojo/shell/public/java/src/org/chromium/mojo/application/ServiceFactoryBinder.java
new file mode 100644
index 0000000..462d74e
--- /dev/null
+++ b/mojo/shell/public/java/src/org/chromium/mojo/application/ServiceFactoryBinder.java
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.mojo.application;
+
+import org.chromium.mojo.bindings.Interface;
+import org.chromium.mojo.system.MessagePipeHandle;
+
+/**
+ * ServiceFactoryBinder holds the necessary information to bind a service interface to a message
+ * pipe.
+ *
+ * @param <T> A mojo service interface.
+ */
+public interface ServiceFactoryBinder<T extends Interface> {
+ /**
+ * An application implements to bind a service implementation to |pipe|.
+ *
+ * @param pipe A handle to the incoming connection pipe.
+ */
+ public void bindNewInstanceToMessagePipe(MessagePipeHandle pipe);
+
+ /**
+ * Name of the service interface being implemented.
+ *
+ * @return Service interface name.
+ */
+ public String getInterfaceName();
+}
diff --git a/mojo/shell/public/java/src/org/chromium/mojo/application/ShellHelper.java b/mojo/shell/public/java/src/org/chromium/mojo/application/ShellHelper.java
new file mode 100644
index 0000000..705e22e
--- /dev/null
+++ b/mojo/shell/public/java/src/org/chromium/mojo/application/ShellHelper.java
@@ -0,0 +1,40 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.mojo.application;
+
+import org.chromium.mojo.bindings.Interface;
+import org.chromium.mojo.bindings.Interface.Proxy;
+import org.chromium.mojo.bindings.InterfaceRequest;
+import org.chromium.mojo.system.Core;
+import org.chromium.mojo.system.Pair;
+import org.chromium.mojom.mojo.ServiceProvider;
+import org.chromium.mojom.mojo.Shell;
+
+/**
+ * Helper class to help connecting to other application through the shell.
+ */
+public class ShellHelper {
+ /**
+ * Connects to a service in another application.
+ *
+ * @param core Implementation of the {@link Core} api.
+ * @param shell Instance of the shell.
+ * @param application URL to the application to use.
+ * @param manager {@link org.chromium.mojo.bindings.Interface.Manager} for the service to
+ * connect to.
+ * @return a proxy to the service.
+ */
+ public static <I extends Interface, P extends Proxy> P connectToService(
+ Core core, Shell shell, String application, Interface.Manager<I, P> manager) {
+ Pair<ServiceProvider.Proxy, InterfaceRequest<ServiceProvider>> providerRequest =
+ ServiceProvider.MANAGER.getInterfaceRequest(core);
+ try (ServiceProvider.Proxy provider = providerRequest.first) {
+ shell.connectToApplication(application, providerRequest.second, null);
+ Pair<P, InterfaceRequest<I>> serviceRequest = manager.getInterfaceRequest(core);
+ provider.connectToService(manager.getName(), serviceRequest.second.passHandle());
+ return serviceRequest.first;
+ }
+ }
+}