// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include "base/bind.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/threading/simple_thread.h" #include "mojo/public/c/system/main.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/shell/public/cpp/application_runner.h" #include "mojo/shell/public/cpp/connector.h" #include "mojo/shell/public/cpp/interface_factory.h" #include "mojo/shell/public/cpp/shell_client.h" #include "mojo/shell/public/interfaces/shell_client_factory.mojom.h" #include "mojo/shell/tests/connect/connect_test.mojom.h" // Tests that multiple applications can be packaged in a single Mojo application // implementing ShellClientFactory; that these applications can be specified by // the package's manifest and are thus registered with the PackageManager. namespace mojo { namespace shell { namespace { void QuitLoop(base::RunLoop* loop) { loop->Quit(); } } using GetTitleCallback = test::mojom::ConnectTestService::GetTitleCallback; class ProvidedShellClient : public ShellClient, public InterfaceFactory, public InterfaceFactory, public InterfaceFactory, public test::mojom::ConnectTestService, public test::mojom::BlockedInterface, public test::mojom::UserIdTest, public base::SimpleThread { public: ProvidedShellClient(const std::string& title, mojom::ShellClientRequest request) : base::SimpleThread(title), title_(title), request_(std::move(request)) { Start(); } ~ProvidedShellClient() override { Join(); } private: // mojo::ShellClient: void Initialize(Connector* connector, const Identity& identity, uint32_t id) override { connector_ = connector; identity_ = identity; id_ = id; bindings_.set_connection_error_handler( base::Bind(&ProvidedShellClient::OnConnectionError, base::Unretained(this))); } bool AcceptConnection(Connection* connection) override { connection->AddInterface(this); connection->AddInterface(this); connection->AddInterface(this); uint32_t remote_id = connection->GetRemoteInstanceID(); test::mojom::ConnectionStatePtr state(test::mojom::ConnectionState::New()); state->connection_local_name = connection->GetConnectionName(); state->connection_remote_name = connection->GetRemoteIdentity().name(); state->connection_remote_userid = connection->GetRemoteIdentity().user_id(); state->connection_remote_id = remote_id; state->initialize_local_name = identity_.name(); state->initialize_id = id_; state->initialize_userid = identity_.user_id(); connection->GetInterface(&caller_); caller_->ConnectionAccepted(std::move(state)); return true; } // InterfaceFactory: void Create(Connection* connection, test::mojom::ConnectTestServiceRequest request) override { bindings_.AddBinding(this, std::move(request)); } // InterfaceFactory: void Create(Connection* connection, test::mojom::BlockedInterfaceRequest request) override { blocked_bindings_.AddBinding(this, std::move(request)); } // InterfaceFactory: void Create(Connection* connection, test::mojom::UserIdTestRequest request) override { user_id_test_bindings_.AddBinding(this, std::move(request)); } // test::mojom::ConnectTestService: void GetTitle(const GetTitleCallback& callback) override { callback.Run(title_); } void GetInstance(const GetInstanceCallback& callback) override { callback.Run(identity_.instance()); } // test::mojom::BlockedInterface: void GetTitleBlocked(const GetTitleBlockedCallback& callback) override { callback.Run("Called Blocked Interface!"); } // test::mojom::UserIdTest: void ConnectToClassAppAsDifferentUser( mojom::IdentityPtr target, const ConnectToClassAppAsDifferentUserCallback& callback) override { Connector::ConnectParams params(target.To()); scoped_ptr connection = connector_->Connect(¶ms); { base::RunLoop loop; connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop)); base::MessageLoop::ScopedNestableTaskAllower allow( base::MessageLoop::current()); loop.Run(); } callback.Run(static_cast(connection->GetResult()), mojom::Identity::From(connection->GetRemoteIdentity())); } // base::SimpleThread: void Run() override { ApplicationRunner(this).Run(request_.PassMessagePipe().release().value(), false); delete this; } void OnConnectionError() { if (bindings_.empty()) base::MessageLoop::current()->QuitWhenIdle(); } Connector* connector_ = nullptr; Identity identity_; uint32_t id_ = shell::mojom::kInvalidInstanceID; const std::string title_; mojom::ShellClientRequest request_; test::mojom::ExposedInterfacePtr caller_; BindingSet bindings_; BindingSet blocked_bindings_; BindingSet user_id_test_bindings_; DISALLOW_COPY_AND_ASSIGN(ProvidedShellClient); }; class ConnectTestShellClient : public ShellClient, public InterfaceFactory, public InterfaceFactory, public mojom::ShellClientFactory, public test::mojom::ConnectTestService { public: ConnectTestShellClient() {} ~ConnectTestShellClient() override {} private: // mojo::ShellClient: void Initialize(Connector* connector, const Identity& identity, uint32_t id) override { identity_ = identity; bindings_.set_connection_error_handler( base::Bind(&ConnectTestShellClient::OnConnectionError, base::Unretained(this))); } bool AcceptConnection(Connection* connection) override { connection->AddInterface(this); connection->AddInterface(this); return true; } // InterfaceFactory: void Create(Connection* connection, mojom::ShellClientFactoryRequest request) override { shell_client_factory_bindings_.AddBinding(this, std::move(request)); } // InterfaceFactory: void Create(Connection* connection, test::mojom::ConnectTestServiceRequest request) override { bindings_.AddBinding(this, std::move(request)); } // mojom::ShellClientFactory: void CreateShellClient(mojom::ShellClientRequest request, const String& name) override { if (name == "mojo:connect_test_a") new ProvidedShellClient("A", std::move(request)); else if (name == "mojo:connect_test_b") new ProvidedShellClient("B", std::move(request)); } // test::mojom::ConnectTestService: void GetTitle(const GetTitleCallback& callback) override { callback.Run("ROOT"); } void GetInstance(const GetInstanceCallback& callback) override { callback.Run(identity_.instance()); } void OnConnectionError() { if (bindings_.empty()) base::MessageLoop::current()->QuitWhenIdle(); } Identity identity_; std::vector> delegates_; BindingSet shell_client_factory_bindings_; BindingSet bindings_; DISALLOW_COPY_AND_ASSIGN(ConnectTestShellClient); }; } // namespace shell } // namespace mojo MojoResult MojoMain(MojoHandle shell_handle) { MojoResult rv = mojo::ApplicationRunner( new mojo::shell::ConnectTestShellClient).Run(shell_handle); return rv; }