blob: ccd03a6a61adf433eec87470f42fc0f87546ef36 [file] [log] [blame]
// 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 <stddef.h>
#include <stdint.h>
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_executor.h"
#include "base/threading/simple_thread.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_executable/service_main.h"
#include "services/service_manager/public/cpp/service_receiver.h"
#include "services/service_manager/tests/connect/connect.test-mojom.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
// Tests that multiple services can be packaged in a single service by
// implementing ServiceFactory; that these services can be specified by
// the package's manifest and are thus registered with the PackageManager.
namespace service_manager {
namespace {
void QuitLoop(base::RunLoop* loop,
mojom::ConnectResult* out_result,
absl::optional<Identity>* out_resolved_identity,
mojom::ConnectResult result,
const absl::optional<Identity>& resolved_identity) {
loop->Quit();
*out_result = result;
*out_resolved_identity = resolved_identity;
}
} // namespace
using GetTitleCallback = test::mojom::ConnectTestService::GetTitleCallback;
class ProvidedService : public Service,
public test::mojom::ConnectTestService,
public test::mojom::BlockedInterface,
public test::mojom::AlwaysAllowedInterface,
public test::mojom::IdentityTest,
public base::SimpleThread {
public:
ProvidedService(const std::string& title,
mojo::PendingReceiver<mojom::Service> receiver)
: base::SimpleThread(title),
title_(title),
receiver_(std::move(receiver)) {
Start();
}
~ProvidedService() override {
Join();
}
private:
// service_manager::Service:
void OnStart() override {
receivers_.set_disconnect_handler(base::BindRepeating(
&ProvidedService::OnMojoDisconnect, base::Unretained(this)));
registry_.AddInterface<test::mojom::ConnectTestService>(
base::BindRepeating(&ProvidedService::BindConnectTestServiceReceiver,
base::Unretained(this)));
registry_.AddInterface<test::mojom::BlockedInterface>(
base::BindRepeating(&ProvidedService::BindBlockedInterfaceReceiver,
base::Unretained(this)));
registry_.AddInterface<test::mojom::AlwaysAllowedInterface>(
base::BindRepeating(
&ProvidedService::BindAlwaysAllowedInterfaceReceiver,
base::Unretained(this)));
registry_.AddInterface(base::BindRepeating(
&ProvidedService::BindIdentityTestReceiver, base::Unretained(this)));
}
void OnBindInterface(const BindSourceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override {
registry_.BindInterface(interface_name, std::move(interface_pipe),
source_info);
}
void OnDisconnected() override {
service_receiver_.Close();
run_loop_->Quit();
}
void BindConnectTestServiceReceiver(
mojo::PendingReceiver<test::mojom::ConnectTestService> receiver,
const BindSourceInfo& source_info) {
receivers_.Add(this, std::move(receiver));
test::mojom::ConnectionStatePtr state(test::mojom::ConnectionState::New());
state->connection_remote_name = source_info.identity.name();
state->connection_remote_instance_group =
source_info.identity.instance_group();
state->initialize_local_name = service_receiver_.identity().name();
state->initialize_local_instance_group =
service_receiver_.identity().instance_group();
service_receiver_.GetConnector()->Connect(
source_info.identity, caller_.BindNewPipeAndPassReceiver());
caller_->ConnectionAccepted(std::move(state));
}
void BindBlockedInterfaceReceiver(
mojo::PendingReceiver<test::mojom::BlockedInterface> receiver,
const BindSourceInfo& source_info) {
blocked_receivers_.Add(this, std::move(receiver));
}
void BindAlwaysAllowedInterfaceReceiver(
mojo::PendingReceiver<test::mojom::AlwaysAllowedInterface> receiver,
const BindSourceInfo& source_info) {
always_allowed_receivers_.Add(this, std::move(receiver));
}
void BindIdentityTestReceiver(
mojo::PendingReceiver<test::mojom::IdentityTest> receiver,
const BindSourceInfo& source_info) {
identity_test_receivers_.Add(this, std::move(receiver));
}
// test::mojom::ConnectTestService:
void GetTitle(GetTitleCallback callback) override {
std::move(callback).Run(title_);
}
void GetInstanceId(GetInstanceIdCallback callback) override {
std::move(callback).Run(service_receiver_.identity().instance_id());
}
// test::mojom::BlockedInterface:
void GetTitleBlocked(GetTitleBlockedCallback callback) override {
std::move(callback).Run("Called Blocked Interface!");
}
// test::mojom::AlwaysAllowedInterface:
void GetTitleAlwaysAllowed(GetTitleAlwaysAllowedCallback callback) override {
std::move(callback).Run("always_allowed");
}
// test::mojom::IdentityTest:
void ConnectToClassAppWithFilter(
const service_manager::ServiceFilter& filter,
ConnectToClassAppWithFilterCallback callback) override {
mojom::ConnectResult result;
absl::optional<Identity> resolved_identity;
base::RunLoop loop(base::RunLoop::Type::kNestableTasksAllowed);
service_receiver_.GetConnector()->WarmService(
filter, base::BindOnce(&QuitLoop, &loop, &result, &resolved_identity));
loop.Run();
std::move(callback).Run(static_cast<int32_t>(result), resolved_identity);
}
// base::SimpleThread:
void Run() override {
base::SingleThreadTaskExecutor main_task_executor;
base::RunLoop run_loop;
run_loop_ = &run_loop;
service_receiver_.Bind(std::move(receiver_));
run_loop.Run();
run_loop_ = nullptr;
caller_.reset();
receivers_.Clear();
blocked_receivers_.Clear();
always_allowed_receivers_.Clear();
identity_test_receivers_.Clear();
}
void OnMojoDisconnect() {
if (receivers_.empty()) {
if (service_receiver_.is_bound())
service_receiver_.Close();
run_loop_->Quit();
}
}
base::RunLoop* run_loop_;
service_manager::ServiceReceiver service_receiver_{this};
const std::string title_;
mojo::PendingReceiver<mojom::Service> receiver_;
mojo::Remote<test::mojom::ExposedInterface> caller_;
BinderRegistryWithArgs<const BindSourceInfo&> registry_;
mojo::ReceiverSet<test::mojom::ConnectTestService> receivers_;
mojo::ReceiverSet<test::mojom::BlockedInterface> blocked_receivers_;
mojo::ReceiverSet<test::mojom::AlwaysAllowedInterface>
always_allowed_receivers_;
mojo::ReceiverSet<test::mojom::IdentityTest> identity_test_receivers_;
DISALLOW_COPY_AND_ASSIGN(ProvidedService);
};
class ConnectTestService : public Service,
public test::mojom::ConnectTestService {
public:
explicit ConnectTestService(
mojo::PendingReceiver<service_manager::mojom::Service> receiver)
: service_receiver_(this, std::move(receiver)) {}
~ConnectTestService() override = default;
private:
// service_manager::Service:
void OnStart() override {
base::RepeatingClosure disconnect_handler = base::BindRepeating(
&ConnectTestService::OnMojoDisconnect, base::Unretained(this));
receivers_.set_disconnect_handler(disconnect_handler);
registry_.AddInterface<test::mojom::ConnectTestService>(
base::BindRepeating(&ConnectTestService::BindConnectTestServiceReceiver,
base::Unretained(this)));
}
void OnBindInterface(const BindSourceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override {
registry_.BindInterface(interface_name, std::move(interface_pipe));
}
void CreatePackagedServiceInstance(
const std::string& service_name,
mojo::PendingReceiver<mojom::Service> receiver,
CreatePackagedServiceInstanceCallback callback) override {
if (service_name == "connect_test_a") {
provided_services_.emplace_back(
std::make_unique<ProvidedService>("A", std::move(receiver)));
} else if (service_name == "connect_test_b") {
provided_services_.emplace_back(
std::make_unique<ProvidedService>("B", std::move(receiver)));
}
std::move(callback).Run(base::GetCurrentProcId());
}
void OnDisconnected() override {
provided_services_.clear();
Terminate();
}
void BindConnectTestServiceReceiver(
mojo::PendingReceiver<test::mojom::ConnectTestService> receiver) {
receivers_.Add(this, std::move(receiver));
}
// test::mojom::ConnectTestService:
void GetTitle(GetTitleCallback callback) override {
std::move(callback).Run("ROOT");
}
void GetInstanceId(GetInstanceIdCallback callback) override {
std::move(callback).Run(service_receiver_.identity().instance_id());
}
void OnMojoDisconnect() {
if (receivers_.empty())
service_receiver_.RequestClose();
}
service_manager::ServiceReceiver service_receiver_;
std::vector<std::unique_ptr<Service>> delegates_;
BinderRegistry registry_;
mojo::ReceiverSet<test::mojom::ConnectTestService> receivers_;
std::list<std::unique_ptr<ProvidedService>> provided_services_;
DISALLOW_COPY_AND_ASSIGN(ConnectTestService);
};
} // namespace service_manager
void ServiceMain(
mojo::PendingReceiver<service_manager::mojom::Service> receiver) {
base::SingleThreadTaskExecutor main_task_executor;
service_manager::ConnectTestService(std::move(receiver))
.RunUntilTermination();
}