blob: 2494479dec78b91a629e5f43f81ceb6c0cca25eb [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/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/threading/simple_thread.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/service_manager/public/c/main.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_context.h"
#include "services/service_manager/public/cpp/service_runner.h"
#include "services/service_manager/public/interfaces/service_factory.mojom.h"
#include "services/service_manager/tests/connect/connect_test.mojom.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,
Identity* out_resolved_identity,
mojom::ConnectResult result,
const 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 InterfaceFactory<test::mojom::ConnectTestService>,
public InterfaceFactory<test::mojom::BlockedInterface>,
public InterfaceFactory<test::mojom::UserIdTest>,
public test::mojom::ConnectTestService,
public test::mojom::BlockedInterface,
public test::mojom::UserIdTest,
public base::SimpleThread {
public:
ProvidedService(const std::string& title, mojom::ServiceRequest request)
: base::SimpleThread(title),
title_(title),
request_(std::move(request)) {
Start();
}
~ProvidedService() override {
Join();
}
private:
// service_manager::Service:
void OnStart() override {
bindings_.set_connection_error_handler(
base::Bind(&ProvidedService::OnConnectionError,
base::Unretained(this)));
registry_.AddInterface<test::mojom::ConnectTestService>(this);
registry_.AddInterface<test::mojom::BlockedInterface>(this);
registry_.AddInterface<test::mojom::UserIdTest>(this);
}
void OnBindInterface(const ServiceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override {
registry_.BindInterface(source_info.identity, interface_name,
std::move(interface_pipe));
}
// InterfaceFactory<test::mojom::ConnectTestService>:
void Create(const Identity& remote_identity,
test::mojom::ConnectTestServiceRequest request) override {
bindings_.AddBinding(this, std::move(request));
test::mojom::ConnectionStatePtr state(test::mojom::ConnectionState::New());
state->connection_remote_name = remote_identity.name();
state->connection_remote_userid = remote_identity.user_id();
state->initialize_local_name = context()->identity().name();
state->initialize_userid = context()->identity().user_id();
context()->connector()->BindInterface(remote_identity, &caller_);
caller_->ConnectionAccepted(std::move(state));
}
// InterfaceFactory<test::mojom::BlockedInterface>:
void Create(const Identity& remote_identity,
test::mojom::BlockedInterfaceRequest request) override {
blocked_bindings_.AddBinding(this, std::move(request));
}
// InterfaceFactory<test::mojom::UserIdTest>:
void Create(const Identity& remote_identity,
test::mojom::UserIdTestRequest request) override {
user_id_test_bindings_.AddBinding(this, std::move(request));
}
// test::mojom::ConnectTestService:
void GetTitle(const GetTitleCallback& callback) override {
callback.Run(title_);
}
void GetInstance(const GetInstanceCallback& callback) override {
callback.Run(context()->identity().instance());
}
// test::mojom::BlockedInterface:
void GetTitleBlocked(const GetTitleBlockedCallback& callback) override {
callback.Run("Called Blocked Interface!");
}
// test::mojom::UserIdTest:
void ConnectToClassAppAsDifferentUser(
const service_manager::Identity& target,
const ConnectToClassAppAsDifferentUserCallback& callback) override {
context()->connector()->StartService(target);
mojom::ConnectResult result;
Identity resolved_identity;
{
base::RunLoop loop;
Connector::TestApi test_api(context()->connector());
test_api.SetStartServiceCallback(
base::Bind(&QuitLoop, &loop, &result, &resolved_identity));
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
loop.Run();
}
callback.Run(static_cast<int32_t>(result), resolved_identity);
}
// base::SimpleThread:
void Run() override {
ServiceRunner(new ForwardingService(this)).Run(
request_.PassMessagePipe().release().value(), false);
caller_.reset();
bindings_.CloseAllBindings();
blocked_bindings_.CloseAllBindings();
user_id_test_bindings_.CloseAllBindings();
}
void OnConnectionError() {
if (bindings_.empty())
base::MessageLoop::current()->QuitWhenIdle();
}
const std::string title_;
mojom::ServiceRequest request_;
test::mojom::ExposedInterfacePtr caller_;
BinderRegistry registry_;
mojo::BindingSet<test::mojom::ConnectTestService> bindings_;
mojo::BindingSet<test::mojom::BlockedInterface> blocked_bindings_;
mojo::BindingSet<test::mojom::UserIdTest> user_id_test_bindings_;
DISALLOW_COPY_AND_ASSIGN(ProvidedService);
};
class ConnectTestService
: public Service,
public InterfaceFactory<mojom::ServiceFactory>,
public InterfaceFactory<test::mojom::ConnectTestService>,
public mojom::ServiceFactory,
public test::mojom::ConnectTestService {
public:
ConnectTestService() {}
~ConnectTestService() override {}
private:
// service_manager::Service:
void OnStart() override {
base::Closure error_handler =
base::Bind(&ConnectTestService::OnConnectionError,
base::Unretained(this));
bindings_.set_connection_error_handler(error_handler);
service_factory_bindings_.set_connection_error_handler(error_handler);
registry_.AddInterface<ServiceFactory>(this);
registry_.AddInterface<test::mojom::ConnectTestService>(this);
}
void OnBindInterface(const ServiceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override {
registry_.BindInterface(source_info.identity, interface_name,
std::move(interface_pipe));
}
bool OnServiceManagerConnectionLost() override {
provided_services_.clear();
return true;
}
// InterfaceFactory<mojom::ServiceFactory>:
void Create(const Identity& remote_identity,
mojom::ServiceFactoryRequest request) override {
service_factory_bindings_.AddBinding(this, std::move(request));
}
// InterfaceFactory<test::mojom::ConnectTestService>:
void Create(const Identity& remote_identity,
test::mojom::ConnectTestServiceRequest request) override {
bindings_.AddBinding(this, std::move(request));
}
// mojom::ServiceFactory:
void CreateService(mojom::ServiceRequest request,
const std::string& name) override {
if (name == "connect_test_a") {
provided_services_.emplace_back(
base::MakeUnique<ProvidedService>("A", std::move(request)));
} else if (name == "connect_test_b") {
provided_services_.emplace_back(
base::MakeUnique<ProvidedService>("B", std::move(request)));
}
}
// test::mojom::ConnectTestService:
void GetTitle(const GetTitleCallback& callback) override {
callback.Run("ROOT");
}
void GetInstance(const GetInstanceCallback& callback) override {
callback.Run(context()->identity().instance());
}
void OnConnectionError() {
if (bindings_.empty() && service_factory_bindings_.empty())
context()->RequestQuit();
}
std::vector<std::unique_ptr<Service>> delegates_;
mojo::BindingSet<mojom::ServiceFactory> service_factory_bindings_;
BinderRegistry registry_;
mojo::BindingSet<test::mojom::ConnectTestService> bindings_;
std::list<std::unique_ptr<ProvidedService>> provided_services_;
DISALLOW_COPY_AND_ASSIGN(ConnectTestService);
};
} // namespace service_manager
MojoResult ServiceMain(MojoHandle service_request_handle) {
service_manager::ServiceRunner runner(
new service_manager::ConnectTestService);
return runner.Run(service_request_handle);
}