| // Copyright 2019 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 "chromecast/external_mojo/external_service_support/external_connector.h" |
| |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/threading/sequenced_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "chromecast/external_mojo/external_service_support/external_service.h" |
| #include "mojo/public/cpp/platform/named_platform_channel.h" |
| #include "mojo/public/cpp/platform/platform_channel_endpoint.h" |
| #include "mojo/public/cpp/system/invitation.h" |
| |
| namespace chromecast { |
| namespace external_service_support { |
| |
| namespace { |
| constexpr base::TimeDelta kConnectRetryDelay = |
| base::TimeDelta::FromMilliseconds(500); |
| } // namespace |
| |
| // static |
| void ExternalConnector::Connect( |
| const std::string& broker_path, |
| base::OnceCallback<void(std::unique_ptr<ExternalConnector>)> callback) { |
| DCHECK(callback); |
| |
| mojo::PlatformChannelEndpoint endpoint = |
| mojo::NamedPlatformChannel::ConnectToServer(broker_path); |
| if (!endpoint.is_valid()) { |
| base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( |
| FROM_HERE, |
| base::BindOnce(&ExternalConnector::Connect, broker_path, |
| std::move(callback)), |
| kConnectRetryDelay); |
| return; |
| } |
| |
| auto invitation = mojo::IncomingInvitation::Accept(std::move(endpoint)); |
| auto pipe = invitation.ExtractMessagePipe(0); |
| if (!pipe) { |
| LOG(ERROR) << "Invalid message pipe"; |
| base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( |
| FROM_HERE, |
| base::BindOnce(&ExternalConnector::Connect, broker_path, |
| std::move(callback)), |
| kConnectRetryDelay); |
| return; |
| } |
| external_mojo::mojom::ExternalConnectorPtr connector( |
| external_mojo::mojom::ExternalConnectorPtrInfo(std::move(pipe), 0)); |
| std::move(callback).Run( |
| std::make_unique<ExternalConnector>(std::move(connector))); |
| } |
| |
| ExternalConnector::ExternalConnector( |
| external_mojo::mojom::ExternalConnectorPtr connector) |
| : connector_(std::move(connector)) { |
| connector_.set_connection_error_handler(base::BindOnce( |
| &ExternalConnector::OnConnectionError, base::Unretained(this))); |
| } |
| |
| ExternalConnector::ExternalConnector( |
| external_mojo::mojom::ExternalConnectorPtrInfo unbound_state) |
| : unbound_state_(std::move(unbound_state)) { |
| DETACH_FROM_SEQUENCE(sequence_checker_); |
| } |
| |
| ExternalConnector::~ExternalConnector() = default; |
| |
| void ExternalConnector::RegisterService(const std::string& service_name, |
| ExternalService* service) { |
| RegisterService(service_name, service->GetBinding()); |
| } |
| |
| void ExternalConnector::RegisterService( |
| const std::string& service_name, |
| external_mojo::mojom::ExternalServicePtr service_ptr) { |
| if (BindConnectorIfNecessary()) { |
| connector_->RegisterServiceInstance(service_name, std::move(service_ptr)); |
| } |
| } |
| |
| void ExternalConnector::BindInterface( |
| const std::string& service_name, |
| const std::string& interface_name, |
| mojo::ScopedMessagePipeHandle interface_pipe) { |
| if (BindConnectorIfNecessary()) { |
| connector_->BindInterface(service_name, interface_name, |
| std::move(interface_pipe)); |
| } |
| } |
| |
| std::unique_ptr<ExternalConnector> ExternalConnector::Clone() { |
| external_mojo::mojom::ExternalConnectorPtrInfo connector_info; |
| auto request = mojo::MakeRequest(&connector_info); |
| if (BindConnectorIfNecessary()) { |
| connector_->Clone(std::move(request)); |
| } |
| return std::make_unique<ExternalConnector>(std::move(connector_info)); |
| } |
| |
| void ExternalConnector::SendChromiumConnectorRequest( |
| mojo::ScopedMessagePipeHandle request) { |
| if (BindConnectorIfNecessary()) { |
| connector_->BindChromiumConnector(std::move(request)); |
| } |
| } |
| |
| void ExternalConnector::OnConnectionError() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| connector_.reset(); |
| if (connection_error_callback_) { |
| std::move(connection_error_callback_).Run(); |
| } |
| } |
| |
| bool ExternalConnector::BindConnectorIfNecessary() { |
| // Bind the message pipe and SequenceChecker to the current thread the first |
| // time it is used to connect. |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (connector_.is_bound()) { |
| return true; |
| } |
| |
| if (!unbound_state_.is_valid()) { |
| // OnConnectionError was already called, but |this| was not destroyed. |
| return false; |
| } |
| |
| connector_.Bind(std::move(unbound_state_)); |
| connector_.set_connection_error_handler(base::BindOnce( |
| &ExternalConnector::OnConnectionError, base::Unretained(this))); |
| |
| return true; |
| } |
| |
| } // namespace external_service_support |
| } // namespace chromecast |