blob: 9132a14e37ada15fbb9529d3199ea40359ed98db [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/broker_service/broker_service.h"
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/message_loop/message_pump_type.h"
#include "base/no_destructor.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/thread.h"
#include "chromecast/external_mojo/public/cpp/common.h"
#include "chromecast/external_mojo/public/cpp/external_mojo_broker.h"
#include "chromecast/external_mojo/public/mojom/connector.mojom.h"
#include "services/service_manager/public/cpp/manifest_builder.h"
namespace chromecast {
namespace external_mojo {
namespace {
BrokerService* g_instance = nullptr;
std::vector<service_manager::Manifest>& GetExternalManifests() {
static std::vector<service_manager::Manifest> manifests;
return manifests;
}
service_manager::Manifest MakePackagedServices(
std::vector<service_manager::Manifest> manifests) {
service_manager::Manifest packaged;
for (auto& manifest : manifests) {
// External services can only access what the external Mojo broker service
// can access, so require all services that external services require.
for (const auto& capability_entry : manifest.required_capabilities) {
const auto& service_name = capability_entry.first;
const auto& capability_names = capability_entry.second;
for (const auto& capability_name : capability_names) {
packaged.required_capabilities[service_name].insert(capability_name);
}
}
// External services that expose capabilities have an internal proxy service
// registered with ServiceManager.
if (!manifest.exposed_capabilities.empty()) {
// The external Mojo broker service needs to require a capability from
// each external service in order to register the internal proxy service
// for it.
packaged.required_capabilities[manifest.service_name].insert(
manifest.exposed_capabilities.begin()->first);
packaged.packaged_services.emplace_back(std::move(manifest));
}
}
return packaged;
}
} // namespace
BrokerService::BrokerService(service_manager::Connector* connector) {
DCHECK(!g_instance);
g_instance = this;
io_thread_ = std::make_unique<base::Thread>("external_mojo");
io_thread_->StartWithOptions(
base::Thread::Options(base::MessagePumpType::IO, 0));
std::vector<std::string> external_services_to_proxy;
const service_manager::Manifest& manifest = GetManifest();
for (const auto& sub_manifest : manifest.packaged_services) {
external_services_to_proxy.push_back(sub_manifest.service_name);
}
bundle_.AddBinder(base::BindRepeating(&BrokerService::BindConnector,
base::Unretained(this)));
broker_ = base::SequenceBound<ExternalMojoBroker>(io_thread_->task_runner(),
GetBrokerPath());
broker_.AsyncCall(&ExternalMojoBroker::InitializeChromium)
.WithArgs(connector->Clone(), external_services_to_proxy);
}
BrokerService::~BrokerService() {
broker_.Reset();
io_thread_.reset();
g_instance = nullptr;
}
// static
BrokerService* BrokerService::GetInstance() {
return g_instance;
}
// static
void BrokerService::ServiceRequestHandler(
mojo::PendingReceiver<service_manager::mojom::Service> receiver) {
if (!g_instance) {
return;
}
g_instance->BindServiceRequest(std::move(receiver));
}
// static
void BrokerService::AddExternalServiceManifest(
service_manager::Manifest manifest) {
GetExternalManifests().push_back(std::move(manifest));
}
// static
const service_manager::Manifest& BrokerService::GetManifest() {
static base::NoDestructor<service_manager::Manifest> manifest{
service_manager::ManifestBuilder()
.WithServiceName(BrokerService::kServiceName)
.WithDisplayName("External Mojo Broker Service")
.WithOptions(service_manager::ManifestOptionsBuilder()
.WithSandboxType("none")
.CanRegisterOtherServiceInstances(true)
.Build())
.ExposeCapability(
"connector_factory",
std::set<const char*>{
"chromecast.external_mojo.mojom.ExternalConnector",
})
.Build()
.Amend(MakePackagedServices(GetExternalManifests()))};
return *manifest;
}
void BrokerService::OnConnect(const service_manager::BindSourceInfo& source,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
bundle_.BindInterface(interface_name, std::move(interface_pipe));
}
void BrokerService::BindConnector(
mojo::PendingReceiver<mojom::ExternalConnector> receiver) {
broker_.AsyncCall(&ExternalMojoBroker::BindConnector)
.WithArgs(std::move(receiver));
}
mojo::PendingRemote<mojom::ExternalConnector> BrokerService::CreateConnector() {
mojo::PendingRemote<mojom::ExternalConnector> connector_remote;
BindConnector(connector_remote.InitWithNewPipeAndPassReceiver());
return connector_remote;
}
void BrokerService::BindServiceRequest(
mojo::PendingReceiver<service_manager::mojom::Service> receiver) {
if (service_receiver_.is_bound()) {
LOG(INFO) << "BrokerService is re-binding to the Service Manager.";
service_receiver_.Close();
}
service_receiver_.Bind(std::move(receiver));
}
} // namespace external_mojo
} // namespace chromecast