Chromium Code Reviews| Index: content/common/mojo/mojo_shell_connection_impl.cc |
| diff --git a/content/common/mojo/mojo_shell_connection_impl.cc b/content/common/mojo/mojo_shell_connection_impl.cc |
| index 6c5ef64a781e49dbfea18901945818a57531d393..65e1bb639d0c8aebffdb5bfd2046137d8e695159 100644 |
| --- a/content/common/mojo/mojo_shell_connection_impl.cc |
| +++ b/content/common/mojo/mojo_shell_connection_impl.cc |
| @@ -4,63 +4,232 @@ |
| #include "content/common/mojo/mojo_shell_connection_impl.h" |
| +#include <utility> |
| +#include <vector> |
| + |
| #include "base/bind.h" |
| +#include "base/callback_helpers.h" |
| #include "base/lazy_instance.h" |
| +#include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| -#include "base/threading/thread_local.h" |
| +#include "base/threading/thread_checker.h" |
| #include "content/common/mojo/embedded_application_runner.h" |
| +#include "mojo/public/cpp/bindings/binding_set.h" |
| +#include "mojo/public/cpp/system/message_pipe.h" |
| #include "services/shell/public/cpp/shell_client.h" |
| #include "services/shell/public/cpp/shell_connection.h" |
| +#include "services/shell/public/interfaces/shell_client_factory.mojom.h" |
| #include "services/shell/runner/common/client_util.h" |
| namespace content { |
| namespace { |
| -using MojoShellConnectionPtr = |
| - base::ThreadLocalPointer<MojoShellConnection>; |
| - |
| -// Env is thread local so that aura may be used on multiple threads. |
| -base::LazyInstance<MojoShellConnectionPtr>::Leaky lazy_tls_ptr = |
| - LAZY_INSTANCE_INITIALIZER; |
| +base::LazyInstance<std::unique_ptr<MojoShellConnection>>::Leaky |
| + g_connection_for_process = LAZY_INSTANCE_INITIALIZER; |
| MojoShellConnection::Factory* mojo_shell_connection_factory = nullptr; |
| } // namespace |
| +// A ref-counted object which owns the IO thread state of a |
| +// MojoShellConnectionImpl. This includes ShellClient and ShellClientFactory |
| +// bindings. |
| +class MojoShellConnectionImpl::IOThreadContext |
| + : public base::RefCountedThreadSafe<IOThreadContext>, |
| + public shell::ShellClient, |
| + public shell::InterfaceFactory<shell::mojom::ShellClientFactory>, |
| + public shell::mojom::ShellClientFactory { |
| + public: |
| + using ShellClientFactoryCallback = |
| + base::Callback<void(shell::mojom::ShellClientRequest, |
| + const mojo::String&)>; |
| + |
| + IOThreadContext() {} |
| + |
| + // The following methods are safe to call from any thread. |
| + |
| + void Initialize(shell::mojom::ShellClientRequest request, |
| + scoped_refptr<base::SequencedTaskRunner> io_task_runner, |
| + std::unique_ptr<shell::Connector> io_thread_connector, |
| + shell::mojom::ConnectorRequest connector_request, |
| + const base::Closure& initialize_callback, |
| + const ShellClientFactoryCallback& create_shell_client) { |
| + DCHECK(!io_task_runner_); |
| + io_thread_checker_.DetachFromThread(); |
| + |
| + io_task_runner_ = io_task_runner; |
| + initialize_handler_ = base::Bind( |
| + &IOThreadContext::CallInitializeOnTaskRunner, |
| + base::ThreadTaskRunnerHandle::Get(), initialize_callback); |
| + |
| + create_shell_client_ = base::Bind( |
| + &IOThreadContext::CallShellClientFactoryOnTaskRunner, |
| + base::ThreadTaskRunnerHandle::Get(), create_shell_client); |
| + |
| + io_task_runner_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&IOThreadContext::InitializeOnIOThread, this, |
| + base::Passed(&request), base::Passed(&io_thread_connector), |
| + base::Passed(&connector_request))); |
| + } |
| + |
| + void ShutDown() { |
| + bool posted = io_task_runner_->PostTask( |
| + FROM_HERE, base::Bind(&IOThreadContext::ShutdownOnIOThread, this)); |
| + |
| + // This must be called before IO thread shutdown. |
| + DCHECK(posted); |
| + } |
| + |
| + void AddConnectionFilter( |
| + const MojoShellConnection::ConnectionFilter& filter) { |
| + base::AutoLock lock(lock_); |
| + connection_filters_.push_back(filter); |
| + } |
| + |
| + shell::Identity GetIdentity() { |
| + base::AutoLock lock(lock_); |
| + if (!shell_connection_) |
| + return shell::Identity(); |
| + |
| + return shell_connection_->identity(); |
| + } |
| + |
| + private: |
| + friend class base::RefCountedThreadSafe<IOThreadContext>; |
| + |
| + ~IOThreadContext() override {} |
| + |
| + void InitializeOnIOThread(shell::mojom::ShellClientRequest request, |
| + std::unique_ptr<shell::Connector> connector, |
| + shell::mojom::ConnectorRequest connector_request) { |
| + // Should bind |io_thread_checker_| to the context's thread. |
| + DCHECK(io_thread_checker_.CalledOnValidThread()); |
| + shell_connection_.reset(new shell::ShellConnection( |
| + this, std::move(request), std::move(connector), |
| + std::move(connector_request))); |
| + } |
| + |
| + void ShutdownOnIOThread() { |
| + DCHECK(io_thread_checker_.CalledOnValidThread()); |
| + shell_connection_.reset(); |
| + factory_bindings_.CloseAllBindings(); |
| + } |
| + |
| + ///////////////////////////////////////////////////////////////////////////// |
| + // shell::ShellClient implementation |
| + |
| + void Initialize(shell::Connector* connector, |
| + const shell::Identity& identity, |
| + uint32_t id) override { |
| + DCHECK(io_thread_checker_.CalledOnValidThread()); |
| + DCHECK(!initialize_handler_.is_null()); |
| + base::ResetAndReturn(&initialize_handler_).Run(); |
| + } |
| + |
| + bool AcceptConnection(shell::Connection* connection) override { |
| + DCHECK(io_thread_checker_.CalledOnValidThread()); |
| + std::string remote_app = connection->GetRemoteIdentity().name(); |
| + if (remote_app == "mojo:shell") { |
| + // Only expose the SCF interface to the shell. |
| + connection->AddInterface<shell::mojom::ShellClientFactory>(this); |
| + return true; |
| + } |
| + |
| + bool accept = false; |
| + base::AutoLock lock(lock_); |
| + for (auto& filter : connection_filters_) |
| + accept = accept || filter.Run(connection, shell_connection_->connector()); |
| + |
| + // Reject all other connections to this application. |
| + return accept; |
| + } |
| + |
| + ///////////////////////////////////////////////////////////////////////////// |
| + // shell::InterfaceFactory<shell::mojom::ShellClientFactory> implementation |
| + |
| + void Create(shell::Connection* connection, |
| + shell::mojom::ShellClientFactoryRequest request) override { |
| + DCHECK(io_thread_checker_.CalledOnValidThread()); |
| + factory_bindings_.AddBinding(this, std::move(request)); |
| + } |
| + |
| + ///////////////////////////////////////////////////////////////////////////// |
| + // shell::mojom::ShellClientFactory implementation |
| + |
| + void CreateShellClient(shell::mojom::ShellClientRequest request, |
| + const mojo::String& name) override { |
| + DCHECK(io_thread_checker_.CalledOnValidThread()); |
| + create_shell_client_.Run(std::move(request), name); |
| + } |
| + |
| + static void CallInitializeOnTaskRunner( |
| + scoped_refptr<base::SequencedTaskRunner> task_runner, |
| + const base::Closure& callback) { |
| + task_runner->PostTask(FROM_HERE, callback); |
| + } |
| + |
| + static void CallShellClientFactoryOnTaskRunner( |
| + scoped_refptr<base::SequencedTaskRunner> task_runner, |
| + const ShellClientFactoryCallback& callback, |
| + shell::mojom::ShellClientRequest request, |
| + const mojo::String& name) { |
| + task_runner->PostTask( |
| + FROM_HERE, base::Bind(callback, base::Passed(&request), name)); |
| + } |
| + |
| + base::ThreadChecker io_thread_checker_; |
| + |
| + scoped_refptr<base::SequencedTaskRunner> io_task_runner_; |
| + |
| + base::Closure initialize_handler_; |
| + ShellClientFactoryCallback create_shell_client_; |
| + |
| + // Guards fields below for thread-safe access. |
| + base::Lock lock_; |
| + |
| + std::unique_ptr<shell::ShellConnection> shell_connection_; |
| + mojo::BindingSet<shell::mojom::ShellClientFactory> factory_bindings_; |
| + std::vector<MojoShellConnection::ConnectionFilter> connection_filters_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(IOThreadContext); |
| +}; |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| // MojoShellConnection, public: |
| // static |
| void MojoShellConnection::SetForProcess( |
| std::unique_ptr<MojoShellConnection> connection) { |
| - DCHECK(!lazy_tls_ptr.Pointer()->Get()); |
| - lazy_tls_ptr.Pointer()->Set(connection.release()); |
| + DCHECK(!g_connection_for_process.Get()); |
| + g_connection_for_process.Get() = std::move(connection); |
| } |
| // static |
| MojoShellConnection* MojoShellConnection::GetForProcess() { |
| - return lazy_tls_ptr.Pointer()->Get(); |
| + return g_connection_for_process.Get().get(); |
| } |
| // static |
| void MojoShellConnection::DestroyForProcess() { |
| // This joins the shell controller thread. |
| - delete GetForProcess(); |
| - lazy_tls_ptr.Pointer()->Set(nullptr); |
| + g_connection_for_process.Get().reset(); |
| } |
| // static |
| void MojoShellConnection::SetFactoryForTest(Factory* factory) { |
| - DCHECK(!lazy_tls_ptr.Pointer()->Get()); |
| + DCHECK(!g_connection_for_process.Get()); |
| mojo_shell_connection_factory = factory; |
| } |
| // static |
| std::unique_ptr<MojoShellConnection> MojoShellConnection::Create( |
| - shell::mojom::ShellClientRequest request) { |
| + shell::mojom::ShellClientRequest request, |
| + scoped_refptr<base::SequencedTaskRunner> io_task_runner) { |
| if (mojo_shell_connection_factory) |
| return mojo_shell_connection_factory->Run(); |
| - return base::WrapUnique(new MojoShellConnectionImpl(std::move(request))); |
| + return base::MakeUnique<MojoShellConnectionImpl>( |
| + std::move(request), io_task_runner); |
| } |
| MojoShellConnection::~MojoShellConnection() {} |
| @@ -69,115 +238,50 @@ MojoShellConnection::~MojoShellConnection() {} |
| // MojoShellConnectionImpl, public: |
| MojoShellConnectionImpl::MojoShellConnectionImpl( |
| - shell::mojom::ShellClientRequest request) |
| - : shell_connection_(new shell::ShellConnection(this, std::move(request))) {} |
| - |
| -MojoShellConnectionImpl::~MojoShellConnectionImpl() {} |
| - |
| -//////////////////////////////////////////////////////////////////////////////// |
| -// MojoShellConnectionImpl, shell::ShellClient implementation: |
| - |
| -void MojoShellConnectionImpl::Initialize(shell::Connector* connector, |
| - const shell::Identity& identity, |
| - uint32_t id) { |
| - for (auto& client : embedded_shell_clients_) |
| - client->Initialize(connector, identity, id); |
| -} |
| - |
| -bool MojoShellConnectionImpl::AcceptConnection(shell::Connection* connection) { |
| - std::string remote_app = connection->GetRemoteIdentity().name(); |
| - if (remote_app == "mojo:shell") { |
| - // Only expose the SCF interface to the shell. |
| - connection->AddInterface<shell::mojom::ShellClientFactory>(this); |
| - return true; |
| - } |
| - |
| - bool accept = false; |
| - for (auto& client : embedded_shell_clients_) |
| - accept |= client->AcceptConnection(connection); |
| - |
| - // Reject all other connections to this application. |
| - return accept; |
| -} |
| - |
| -shell::InterfaceRegistry* |
| -MojoShellConnectionImpl::GetInterfaceRegistryForConnection() { |
| - // TODO(beng): This is really horrible since obviously subject to issues |
| - // of ordering, but is no more horrible than this API is in general. |
| - shell::InterfaceRegistry* registry = nullptr; |
| - for (auto& client : embedded_shell_clients_) { |
| - registry = client->GetInterfaceRegistryForConnection(); |
| - if (registry) |
| - return registry; |
| - } |
| - return nullptr; |
| -} |
| - |
| -shell::InterfaceProvider* |
| -MojoShellConnectionImpl::GetInterfaceProviderForConnection() { |
| - // TODO(beng): This is really horrible since obviously subject to issues |
| - // of ordering, but is no more horrible than this API is in general. |
| - shell::InterfaceProvider* provider = nullptr; |
| - for (auto& client : embedded_shell_clients_) { |
| - provider = client->GetInterfaceProviderForConnection(); |
| - if (provider) |
| - return provider; |
| - } |
| - return nullptr; |
| -} |
| - |
| -//////////////////////////////////////////////////////////////////////////////// |
| -// MojoShellConnectionImpl, |
| -// shell::InterfaceFactory<shell::mojom::ShellClientFactory> implementation: |
| - |
| -void MojoShellConnectionImpl::Create( |
| - shell::Connection* connection, |
| - shell::mojom::ShellClientFactoryRequest request) { |
| - factory_bindings_.AddBinding(this, std::move(request)); |
| + shell::mojom::ShellClientRequest request, |
| + scoped_refptr<base::SequencedTaskRunner> io_task_runner) |
| + : context_(new IOThreadContext), weak_factory_(this) { |
| + shell::mojom::ConnectorRequest connector_request; |
| + connector_ = shell::Connector::Create(&connector_request); |
| + |
| + std::unique_ptr<shell::Connector> io_thread_connector = connector_->Clone(); |
| + context_->Initialize( |
| + std::move(request), io_task_runner, std::move(io_thread_connector), |
| + std::move(connector_request), |
| + base::Bind(&MojoShellConnectionImpl::OnContextInitialized, |
| + weak_factory_.GetWeakPtr()), |
| + base::Bind(&MojoShellConnectionImpl::CreateShellClient, |
| + weak_factory_.GetWeakPtr())); |
| } |
| -//////////////////////////////////////////////////////////////////////////////// |
| -// MojoShellConnectionImpl, shell::mojom::ShellClientFactory implementation: |
| - |
| -void MojoShellConnectionImpl::CreateShellClient( |
| - shell::mojom::ShellClientRequest request, |
| - const mojo::String& name) { |
| - auto it = request_handlers_.find(name); |
| - if (it != request_handlers_.end()) |
| - it->second.Run(std::move(request)); |
| +MojoShellConnectionImpl::~MojoShellConnectionImpl() { |
| + context_->ShutDown(); |
| } |
| //////////////////////////////////////////////////////////////////////////////// |
| // MojoShellConnectionImpl, MojoShellConnection implementation: |
| -shell::ShellConnection* MojoShellConnectionImpl::GetShellConnection() { |
| - return shell_connection_.get(); |
| +void MojoShellConnectionImpl::SetInitializeHandler( |
| + const base::Closure& handler) { |
| + DCHECK(initialize_handler_.is_null()); |
| + initialize_handler_ = handler; |
| } |
| shell::Connector* MojoShellConnectionImpl::GetConnector() { |
| - DCHECK(shell_connection_); |
| - return shell_connection_->connector(); |
| + return connector_.get(); |
| } |
| const shell::Identity& MojoShellConnectionImpl::GetIdentity() const { |
| - DCHECK(shell_connection_); |
| - return shell_connection_->identity(); |
| + return identity_; |
| } |
| void MojoShellConnectionImpl::SetConnectionLostClosure( |
| const base::Closure& closure) { |
| - shell_connection_->SetConnectionLostClosure(closure); |
| -} |
| - |
| -void MojoShellConnectionImpl::AddEmbeddedShellClient( |
| - std::unique_ptr<shell::ShellClient> shell_client) { |
| - embedded_shell_clients_.push_back(shell_client.get()); |
| - owned_shell_clients_.push_back(std::move(shell_client)); |
| + connection_lost_handler_ = closure; |
| } |
| -void MojoShellConnectionImpl::AddEmbeddedShellClient( |
| - shell::ShellClient* shell_client) { |
| - embedded_shell_clients_.push_back(shell_client); |
| +void MojoShellConnectionImpl::AddConnectionFilter( |
| + const ConnectionFilter& filter) { |
|
Ben Goodger (Google)
2016/07/03 03:29:27
did you mean to leave this implementation empty?
|
| } |
| void MojoShellConnectionImpl::AddEmbeddedService( |
| @@ -199,4 +303,23 @@ void MojoShellConnectionImpl::AddShellClientRequestHandler( |
| DCHECK(result.second); |
| } |
| +void MojoShellConnectionImpl::CreateShellClient( |
| + shell::mojom::ShellClientRequest request, |
| + const mojo::String& name) { |
| + auto it = request_handlers_.find(name); |
| + if (it != request_handlers_.end()) |
| + it->second.Run(std::move(request)); |
| +} |
| + |
| +void MojoShellConnectionImpl::OnContextInitialized() { |
| + identity_ = context_->GetIdentity(); |
| + if (!initialize_handler_.is_null()) |
| + base::ResetAndReturn(&initialize_handler_).Run(); |
| +} |
| + |
| +void MojoShellConnectionImpl::OnConnectionLost() { |
| + if (!connection_lost_handler_.is_null()) |
| + connection_lost_handler_.Run(); |
| +} |
| + |
| } // namespace content |