Add an ApplicationConnector interface, etc.
Also do a bit of (minimal) cleanup of ApplicationImpl.
From the Shell interface, you can mint ApplicationConnectors, which
allows you to connect to other applications. This is useful if you want
to connect to applications from other threads or other environments
(e.g., inside a VM).
TODO(vtl): Maybe add a Duplicate() to ApplicationConnector. The reason
we don't just add a Duplicate() to Shell is that Shell is associated
with low-level stuff (e.g., process lifetime), and we may want to add
more low-level process-y stuff (which shouldn't be delegated) to it in
the future.
R=jamesr@chromium.org
Review URL: https://codereview.chromium.org/1435153003 .
diff --git a/mojo/go/tests/application_impl_test.go b/mojo/go/tests/application_impl_test.go
index b28c95f..5335ae8 100644
--- a/mojo/go/tests/application_impl_test.go
+++ b/mojo/go/tests/application_impl_test.go
@@ -14,6 +14,7 @@
"examples/echo/echo"
mojoApp "mojo/public/interfaces/application/application"
+ ac "mojo/public/interfaces/application/application_connector"
sp "mojo/public/interfaces/application/service_provider"
"mojo/public/interfaces/application/shell"
)
@@ -120,6 +121,11 @@
return nil
}
+func (s *shellImpl) CreateApplicationConnector(applicationConnectorRequest ac.ApplicationConnector_Request) error {
+ // TODO(vtl): https://github.com/domokit/mojo/issues/533
+ panic("not implemented")
+}
+
func TestApplication(t *testing.T) {
var apps []*mojoApp.Application_Proxy
var responsesSent, appsTerminated sync.WaitGroup
diff --git a/mojo/public/cpp/application/application_impl.h b/mojo/public/cpp/application/application_impl.h
index e456de0..6fba0dd 100644
--- a/mojo/public/cpp/application/application_impl.h
+++ b/mojo/public/cpp/application/application_impl.h
@@ -5,6 +5,7 @@
#ifndef MOJO_PUBLIC_APPLICATION_APPLICATION_IMPL_H_
#define MOJO_PUBLIC_APPLICATION_APPLICATION_IMPL_H_
+#include <memory>
#include <string>
#include <vector>
@@ -12,6 +13,7 @@
#include "mojo/public/cpp/application/lib/service_registry.h"
#include "mojo/public/cpp/system/core.h"
#include "mojo/public/interfaces/application/application.mojom.h"
+#include "mojo/public/interfaces/application/application_connector.mojom.h"
#include "mojo/public/interfaces/application/shell.mojom.h"
namespace mojo {
@@ -39,6 +41,11 @@
InterfaceRequest<Application> request);
~ApplicationImpl() override;
+ // Quits the main run loop for this application.
+ // TODO(vtl): This is implemented in application_runner.cc (for example). Its
+ // presence here is pretty dubious.
+ static void Terminate();
+
// 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.
@@ -50,27 +57,31 @@
const std::vector<std::string>& args() const { return args_; }
bool HasArg(const std::string& arg) const;
+ // Creates a new |ApplicationConnector|. The result can be bound to an
+ // |ApplicationConnectorPtr| and used to connect to other applications. (It
+ // returns an |InterfacePtrInfo| instead of an |InterfacePtr| to facilitate
+ // passing it to another thread.)
+ InterfacePtrInfo<ApplicationConnector> CreateApplicationConnector();
+
// 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 does not take ownership. The pointer remains
// valid until an error occurs on the connection with the Shell, or until the
// ApplicationImpl is destroyed, whichever occurs first.
+ // TODO(vtl): Deprecate/remove this.
ApplicationConnection* ConnectToApplication(const String& application_url);
// Connect to application identified by |application_url| and connect to the
// service implementation of the interface identified by |Interface|.
+ // TODO(vtl): Deprecate/remove this.
template <typename Interface>
void ConnectToService(const std::string& application_url,
InterfacePtr<Interface>* ptr) {
ConnectToApplication(application_url)->ConnectToService(ptr);
}
- // Application implementation.
- void Initialize(ShellPtr shell,
- Array<String> args,
- const mojo::String& url) override;
-
- // Block until the Application is initialized, if it is not already.
+ // Blocks until the |Application| is initialized (i.e., |Initialize()| is
+ // received), if it is not already.
void WaitForInitialize();
// Unbinds the Shell and Application connections. Can be used to re-bind the
@@ -79,30 +90,19 @@
void UnbindConnections(InterfaceRequest<Application>* application_request,
ShellPtr* shell);
- // Quits the main run loop for this application.
- static void Terminate();
-
- protected:
- // Application implementation.
+ // |Application| implementation.
+ void Initialize(ShellPtr shell,
+ Array<String> args,
+ const mojo::String& url) override;
void AcceptConnection(const String& requestor_url,
InterfaceRequest<ServiceProvider> services,
ServiceProviderPtr exposed_services,
const String& url) override;
-
- private:
- void ClearConnections();
-
- void OnShellError() {
- delegate_->Quit();
- ClearConnections();
- Terminate();
- }
-
- // Application implementation.
void RequestQuit() override;
- typedef std::vector<internal::ServiceRegistry*> ServiceRegistryList;
-
+ private:
+ using ServiceRegistryList =
+ std::vector<std::unique_ptr<internal::ServiceRegistry>>;
ServiceRegistryList incoming_service_registries_;
ServiceRegistryList outgoing_service_registries_;
ApplicationDelegate* delegate_;
diff --git a/mojo/public/cpp/application/connect.h b/mojo/public/cpp/application/connect.h
index 964c55f..fb47f5e 100644
--- a/mojo/public/cpp/application/connect.h
+++ b/mojo/public/cpp/application/connect.h
@@ -5,6 +5,7 @@
#ifndef MOJO_PUBLIC_CPP_APPLICATION_CONNECT_H_
#define MOJO_PUBLIC_CPP_APPLICATION_CONNECT_H_
+#include "mojo/public/interfaces/application/application_connector.mojom.h"
#include "mojo/public/interfaces/application/service_provider.mojom.h"
#include "mojo/public/interfaces/application/shell.mojom.h"
@@ -30,6 +31,17 @@
ConnectToService(service_provider.get(), ptr);
}
+// Binds |ptr| to a remote implementation of Interface from |application_url|.
+template <typename Interface>
+inline void ConnectToService(ApplicationConnector* application_connector,
+ const std::string& application_url,
+ InterfacePtr<Interface>* ptr) {
+ ServiceProviderPtr service_provider;
+ application_connector->ConnectToApplication(
+ application_url, GetProxy(&service_provider), nullptr);
+ ConnectToService(service_provider.get(), ptr);
+}
+
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_APPLICATION_CONNECT_H_
diff --git a/mojo/public/cpp/application/lib/application_impl.cc b/mojo/public/cpp/application/lib/application_impl.cc
index 589159c..a468262 100644
--- a/mojo/public/cpp/application/lib/application_impl.cc
+++ b/mojo/public/cpp/application/lib/application_impl.cc
@@ -4,37 +4,34 @@
#include "mojo/public/cpp/application/application_impl.h"
+#include <utility>
+
#include "mojo/public/cpp/application/application_delegate.h"
#include "mojo/public/cpp/application/lib/service_registry.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/public/cpp/system/message_pipe.h"
namespace mojo {
ApplicationImpl::ApplicationImpl(ApplicationDelegate* delegate,
InterfaceRequest<Application> request)
- : delegate_(delegate), binding_(this, request.Pass()) {
-}
+ : delegate_(delegate), binding_(this, request.Pass()) {}
+
+ApplicationImpl::~ApplicationImpl() {}
bool ApplicationImpl::HasArg(const std::string& arg) const {
return std::find(args_.begin(), args_.end(), arg) != args_.end();
}
-void ApplicationImpl::ClearConnections() {
- for (ServiceRegistryList::iterator i(incoming_service_registries_.begin());
- i != incoming_service_registries_.end();
- ++i)
- delete *i;
- for (ServiceRegistryList::iterator i(outgoing_service_registries_.begin());
- i != outgoing_service_registries_.end();
- ++i)
- delete *i;
- incoming_service_registries_.clear();
- outgoing_service_registries_.clear();
-}
-
-ApplicationImpl::~ApplicationImpl() {
- ClearConnections();
+InterfacePtrInfo<ApplicationConnector>
+ApplicationImpl::CreateApplicationConnector() {
+ MOJO_CHECK(shell_);
+ MessagePipe pipe;
+ shell_->CreateApplicationConnector(
+ MakeRequest<ApplicationConnector>(pipe.handle1.Pass()));
+ return InterfacePtrInfo<ApplicationConnector>(pipe.handle0.Pass(), 0u);
}
ApplicationConnection* ApplicationImpl::ConnectToApplication(
@@ -48,20 +45,10 @@
internal::ServiceRegistry* registry = new internal::ServiceRegistry(
this, application_url, application_url, remote_services.Pass(),
local_request.Pass());
- outgoing_service_registries_.push_back(registry);
+ outgoing_service_registries_.emplace_back(registry);
return registry;
}
-void ApplicationImpl::Initialize(ShellPtr shell,
- Array<String> args,
- const mojo::String& url) {
- shell_ = shell.Pass();
- shell_.set_connection_error_handler([this]() { OnShellError(); });
- url_ = url;
- args_ = args.To<std::vector<std::string>>();
- delegate_->Initialize(this);
-}
-
void ApplicationImpl::WaitForInitialize() {
if (!shell_)
binding_.WaitForIncomingMethodCall();
@@ -74,18 +61,32 @@
shell->Bind(shell_.PassInterface());
}
+void ApplicationImpl::Initialize(ShellPtr shell,
+ Array<String> args,
+ const mojo::String& url) {
+ shell_ = shell.Pass();
+ shell_.set_connection_error_handler([this]() {
+ delegate_->Quit();
+ incoming_service_registries_.clear();
+ outgoing_service_registries_.clear();
+ Terminate();
+ });
+ url_ = url;
+ args_ = args.To<std::vector<std::string>>();
+ delegate_->Initialize(this);
+}
+
void ApplicationImpl::AcceptConnection(
const String& requestor_url,
InterfaceRequest<ServiceProvider> services,
ServiceProviderPtr exposed_services,
const String& url) {
- internal::ServiceRegistry* registry = new internal::ServiceRegistry(
- this, url, requestor_url, exposed_services.Pass(), services.Pass());
- if (!delegate_->ConfigureIncomingConnection(registry)) {
- delete registry;
+ std::unique_ptr<internal::ServiceRegistry> registry(
+ new internal::ServiceRegistry(this, url, requestor_url,
+ exposed_services.Pass(), services.Pass()));
+ if (!delegate_->ConfigureIncomingConnection(registry.get()))
return;
- }
- incoming_service_registries_.push_back(registry);
+ incoming_service_registries_.push_back(std::move(registry));
}
void ApplicationImpl::RequestQuit() {
diff --git a/mojo/public/interfaces/application/BUILD.gn b/mojo/public/interfaces/application/BUILD.gn
index 463df55..1d1a173 100644
--- a/mojo/public/interfaces/application/BUILD.gn
+++ b/mojo/public/interfaces/application/BUILD.gn
@@ -8,6 +8,7 @@
mojom("application") {
sources = [
"application.mojom",
+ "application_connector.mojom",
"service_provider.mojom",
"shell.mojom",
]
diff --git a/mojo/public/interfaces/application/application_connector.mojom b/mojo/public/interfaces/application/application_connector.mojom
new file mode 100644
index 0000000..0d08ee9
--- /dev/null
+++ b/mojo/public/interfaces/application/application_connector.mojom
@@ -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.
+
+[DartPackage="mojo"]
+module mojo;
+
+import "mojo/public/interfaces/application/service_provider.mojom";
+
+interface ApplicationConnector {
+ // Establishes a connection with another application (located at
+ // |application_url|) through which the calling application and the other
+ // application may request services from one another.
+ //
+ // If the calling application would like to request services from the other
+ // application, it should pass a valid interface request in the |services|
+ // parameter (i.e. one containing a valid message pipe endpoint). If the other
+ // 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 other
+ // application, it should pass a bound interface through the
+ // |exposed_services| parameter. The other 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.
+ ConnectToApplication(string application_url,
+ ServiceProvider&? services,
+ ServiceProvider? exposed_services);
+};
diff --git a/mojo/public/interfaces/application/shell.mojom b/mojo/public/interfaces/application/shell.mojom
index b2d8491..dc210c7 100644
--- a/mojo/public/interfaces/application/shell.mojom
+++ b/mojo/public/interfaces/application/shell.mojom
@@ -5,35 +5,18 @@
[DartPackage="mojo"]
module mojo;
+import "mojo/public/interfaces/application/application_connector.mojom";
import "mojo/public/interfaces/application/service_provider.mojom";
// An interface through which a Mojo application may communicate with the Mojo
// system and request connections to other applications.
interface Shell {
- // Establishes a connection with another application (located at
- // |application_url|) through which the calling application and the other
- // application may request services from one another.
- //
- // If the calling application would like to request services from the other
- // application, it should pass a valid interface request in the |services|
- // parameter (i.e. one containing a valid message pipe endpoint). If the other
- // 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 other
- // application, it should pass a bound interface through the
- // |exposed_services| parameter. The other 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.
+ // See |ApplicationConnector.ConnectToApplication()|.
+ // TODO(vtl): Maybe this should be deprecated/removed.
ConnectToApplication(string application_url,
ServiceProvider&? services,
ServiceProvider? exposed_services);
+
+ CreateApplicationConnector(
+ ApplicationConnector& application_connector_request);
};
diff --git a/shell/BUILD.gn b/shell/BUILD.gn
index 0919596..a09eb67 100644
--- a/shell/BUILD.gn
+++ b/shell/BUILD.gn
@@ -650,6 +650,7 @@
"//mojo/public/cpp/bindings:callback",
"//mojo/public/cpp/environment",
"//mojo/public/cpp/system:system",
+ "//mojo/public/interfaces/application",
"//mojo/services/http_server/cpp",
"//mojo/services/http_server/interfaces",
"//mojo/services/network/interfaces",
diff --git a/shell/application_manager/BUILD.gn b/shell/application_manager/BUILD.gn
index 9a9cf0c..dac121c 100644
--- a/shell/application_manager/BUILD.gn
+++ b/shell/application_manager/BUILD.gn
@@ -44,6 +44,7 @@
"//base/third_party/dynamic_annotations",
"//crypto:crypto",
"//url",
+ "//mojo/common",
"//mojo/edk/system",
"//mojo/environment:chromium",
"//mojo/services/content_handler/interfaces",
diff --git a/shell/application_manager/shell_impl.cc b/shell/application_manager/shell_impl.cc
index f75c028..4d0532e 100644
--- a/shell/application_manager/shell_impl.cc
+++ b/shell/application_manager/shell_impl.cc
@@ -21,7 +21,8 @@
identity_(identity),
on_application_end_(on_application_end),
application_(application.Pass()),
- binding_(this) {
+ binding_(this),
+ application_connector_impl_(this) {
binding_.set_connection_error_handler(
[this]() { manager_->OnShellImplError(this); });
}
@@ -45,7 +46,6 @@
requested_url.spec());
}
-// Shell implementation:
void ShellImpl::ConnectToApplication(
const mojo::String& app_url,
mojo::InterfaceRequest<ServiceProvider> services,
@@ -59,4 +59,11 @@
exposed_services.Pass(), base::Closure());
}
+void ShellImpl::CreateApplicationConnector(
+ mojo::InterfaceRequest<mojo::ApplicationConnector>
+ application_connector_request) {
+ application_connectors_.AddBinding(&application_connector_impl_,
+ application_connector_request.Pass());
+}
+
} // namespace shell
diff --git a/shell/application_manager/shell_impl.h b/shell/application_manager/shell_impl.h
index 0155720..2fc4846 100644
--- a/shell/application_manager/shell_impl.h
+++ b/shell/application_manager/shell_impl.h
@@ -6,8 +6,11 @@
#define SHELL_APPLICATION_MANAGER_SHELL_IMPL_H_
#include "base/callback.h"
+#include "base/macros.h"
+#include "mojo/common/binding_set.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/interfaces/application/application.mojom.h"
+#include "mojo/public/interfaces/application/application_connector.mojom.h"
#include "mojo/public/interfaces/application/shell.mojom.h"
#include "shell/application_manager/identity.h"
#include "url/gurl.h"
@@ -16,6 +19,11 @@
class ApplicationManager;
+// TODO(vtl): This both implements the |Shell| interface and holds the
+// |ApplicationPtr| (from back when they were paired interfaces on the same
+// message pipe). The way it manages lifetime is dubious/wrong. We should have
+// an object holding stuff associated to an application, namely its "real"
+// |ShellImpl|, its |ApplicationPtr|, and tracking its |ApplicationConnector|s.
class ShellImpl : public mojo::Shell {
public:
ShellImpl(mojo::ApplicationPtr application,
@@ -37,11 +45,32 @@
base::Closure on_application_end() const { return on_application_end_; }
private:
+ class ApplicationConnectorImpl : public mojo::ApplicationConnector {
+ public:
+ explicit ApplicationConnectorImpl(mojo::Shell* shell) : shell_(shell) {}
+ ~ApplicationConnectorImpl() override {}
+
+ void ConnectToApplication(
+ const mojo::String& app_url,
+ mojo::InterfaceRequest<mojo::ServiceProvider> services,
+ mojo::ServiceProviderPtr exposed_services) override {
+ shell_->ConnectToApplication(app_url, services.Pass(),
+ exposed_services.Pass());
+ }
+
+ private:
+ mojo::Shell* const shell_;
+ DISALLOW_COPY_AND_ASSIGN(ApplicationConnectorImpl);
+ };
+
// mojo::Shell implementation:
void ConnectToApplication(
const mojo::String& app_url,
mojo::InterfaceRequest<mojo::ServiceProvider> services,
mojo::ServiceProviderPtr exposed_services) override;
+ void CreateApplicationConnector(
+ mojo::InterfaceRequest<mojo::ApplicationConnector>
+ application_connector_request) override;
ApplicationManager* const manager_;
const Identity identity_;
@@ -49,6 +78,9 @@
mojo::ApplicationPtr application_;
mojo::Binding<mojo::Shell> binding_;
+ ApplicationConnectorImpl application_connector_impl_;
+ mojo::BindingSet<mojo::ApplicationConnector> application_connectors_;
+
DISALLOW_COPY_AND_ASSIGN(ShellImpl);
};
diff --git a/shell/shell_apptest.cc b/shell/shell_apptest.cc
index 1011e24..7bc5e85 100644
--- a/shell/shell_apptest.cc
+++ b/shell/shell_apptest.cc
@@ -13,7 +13,9 @@
#include "mojo/data_pipe_utils/data_pipe_utils.h"
#include "mojo/public/cpp/application/application_impl.h"
#include "mojo/public/cpp/application/application_test_base.h"
+#include "mojo/public/cpp/application/connect.h"
#include "mojo/public/cpp/system/macros.h"
+#include "mojo/public/interfaces/application/application_connector.mojom.h"
#include "mojo/services/http_server/cpp/http_server_util.h"
#include "mojo/services/http_server/interfaces/http_server.mojom.h"
#include "mojo/services/http_server/interfaces/http_server_factory.mojom.h"
@@ -195,4 +197,21 @@
base::RunLoop().Run();
}
+TEST_F(ShellAppTest, ApplicationConnector) {
+ mojo::ApplicationConnectorPtr app_connector;
+ app_connector.Bind(application_impl()->CreateApplicationConnector());
+
+ PingablePtr pingable;
+ ConnectToService(app_connector.get(), "mojo:pingable_app", &pingable);
+ auto callback = [this](const String& app_url, const String& connection_url,
+ const String& message) {
+ EXPECT_TRUE(EndsWith(app_url, "/pingable_app.mojo", true));
+ EXPECT_EQ(app_url, connection_url);
+ EXPECT_EQ("hello", message);
+ base::MessageLoop::current()->Quit();
+ };
+ pingable->Ping("hello", callback);
+ base::RunLoop().Run();
+}
+
} // namespace