blob: 388d3416939fd86be3ceaa15585c3ea9af279d08 [file] [log] [blame]
// 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