blob: 734c3bb4aedec19095fb9263bc7efaa6474bf5a1 [file] [log] [blame]
// Copyright 2017 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.
#ifndef SERVICES_SERVICE_MANAGER_PUBLIC_CPP_CONNECTOR_H_
#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_CONNECTOR_H_
#include <map>
#include <memory>
#include <utility>
#include "base/callback.h"
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/service_manager/public/cpp/export.h"
#include "services/service_manager/public/cpp/identity.h"
#include "services/service_manager/public/mojom/connector.mojom.h"
#include "services/service_manager/public/mojom/service.mojom-forward.h"
#include "services/service_manager/public/mojom/service_manager.mojom-forward.h"
namespace service_manager {
// An interface that encapsulates the Service Manager's brokering interface, by
// which connections between services are established. Once any public methods
// are called on an instance of this class, that instance is bound to the
// calling thread.
//
// To use the same interface on another thread, call Clone() and pass the new
// instance to the desired thread before calling any public methods on it.
class SERVICE_MANAGER_PUBLIC_CPP_EXPORT Connector {
public:
// DEPRECATED: Do not introduce new uses of this API. Just call the public
// *ForTesting methods directly on the Connector. Also see the note on those
// methods about preferring TestConnectorFactory where feasible.
class TestApi {
public:
using Binder = base::RepeatingCallback<void(mojo::ScopedMessagePipeHandle)>;
explicit TestApi(Connector* connector) : connector_(connector) {}
~TestApi() = default;
// Allows caller to specify a callback to bind requests for |interface_name|
// from |service_name| locally, rather than passing the request through the
// Service Manager.
void OverrideBinderForTesting(const service_manager::ServiceFilter& filter,
const std::string& interface_name,
const Binder& binder) {
connector_->OverrideBinderForTesting(filter, interface_name, binder);
}
bool HasBinderOverride(const service_manager::ServiceFilter& filter,
const std::string& interface_name) {
return connector_->HasBinderOverrideForTesting(filter, interface_name);
}
void ClearBinderOverride(const service_manager::ServiceFilter& filter,
const std::string& interface_name) {
connector_->ClearBinderOverrideForTesting(filter, interface_name);
}
void ClearBinderOverrides() {
connector_->ClearBinderOverridesForTesting();
}
private:
Connector* connector_;
};
explicit Connector(mojom::ConnectorPtrInfo unbound_state);
explicit Connector(mojom::ConnectorPtr connector);
~Connector();
// Creates a new Connector instance and fills in |*request| with a request
// for the other end the Connector's interface.
static std::unique_ptr<Connector> Create(mojom::ConnectorRequest* request);
// Asks the Service Manager to ensure that there's a running service instance
// which would match |filter| from the caller's perspective. Useful when
// future |BindInterface()| calls will be made with the same |filter| and
// reducing their latency is a high priority.
//
// Note that there is no value in calling this *immediately* before
// |BindInterface()|, so only use it if there is some delay between when you
// know you will want to talk to a service and when you actually need to for
// the first time. For example, Chrome warms the Network Service ASAP on
// startup so that it can be brought up in parallel while the browser is
// initializing other subsystems.
//
// |callback| conveys information about the result of the request. See
// documentation on the mojom ConnectResult definition for the meaning of
// |result|. If |result| is |SUCCEEDED|, then |identity| will contain the full
// identity of the matching service instance, which was either already running
// or was started as a result of this request.
using WarmServiceCallback =
base::OnceCallback<void(mojom::ConnectResult result,
const base::Optional<Identity>& identity)>;
void WarmService(const ServiceFilter& filter,
WarmServiceCallback callback = {});
// Creates an instance of a service for |identity| in a process started by the
// client (or someone else). Must be called before any |BindInterface()|
// reaches the Service Manager expecting the instance to exist, otherwise the
// Service Manager may attempt to start a new instance on its own, which will
// invariably fail (if the Service Manager knew how to start the instance, the
// caller wouldn't need to use this API).
//
// NOTE: |identity| must be a complete service Identity (including a random
// globally unique ID), and this call will only succeed if the calling service
// has set |can_create_other_service_instances| option to |true| in its
// manifest. This is considered privileged behavior.
using RegisterServiceInstanceCallback =
base::OnceCallback<void(mojom::ConnectResult result)>;
void RegisterServiceInstance(
const Identity& identity,
mojo::PendingRemote<mojom::Service> service,
mojo::PendingReceiver<mojom::ProcessMetadata> metadata_receiver,
RegisterServiceInstanceCallback callback = {});
// Determines if the service for |service_name| is known, and returns
// information about it from the catalog.
void QueryService(const std::string& service_name,
mojom::Connector::QueryServiceCallback callback);
// All variants of |Connect()| ask the Service Manager to route a
// |mojo::Receiver<T>| for any interface type T to a service instance
// identified by a ServiceFilter. If no running service instance matches the
// provided ServiceFilter, the Service Manager may start a new instance which
// does, before routing the Receiver to it.
template <typename Interface>
void Connect(const ServiceFilter& filter,
mojo::PendingReceiver<Interface> receiver) {
BindInterface(filter,
mojo::InterfaceRequest<Interface>(std::move(receiver)));
}
// A variant of the above which constructs a simple ServiceFilter by service
// name only. This will route the Receiver to any available instance of the
// named service.
template <typename Interface>
void Connect(const std::string& service_name,
mojo::PendingReceiver<Interface> receiver) {
Connect(ServiceFilter::ByName(service_name), std::move(receiver));
}
// DEPRECATED: Prefer |Connect()| above. |BindInterface()| uses deprecated
// InterfaceRequest and InterfacePtr types.
//
// All variants of |BindInterface()| ask the Service Manager to route an
// interface request to a service instance matching |filter|. If no running
// service instance matches |filter|, the Service Manager may start a new
// service instance which does, and then route the request to it. See the
// comments in connector.mojom regarding restrictions on when the Service
// Manager will *not* create a new instance or when |filter| may otherwise be
// rejected.
//
// For variants which take a callback, |callback| conveys information about
// the result of the request. See documentation on the mojom ConnectResult
// definition for the meaning of |result|. If |result| is |SUCCEEDED|, then
// |identity| will contain the full identity of the matching service instance
// to which the interface request was routed. This service instance was either
// already running, or was started as a result of this request.
//
// TODO: We should consider removing some of these overloads as they're quite
// redundant. It would be cleaner to just have callers explicitly construct a
// ServiceFilter and InterfaceRequest rather than having a bunch of template
// helpers to do the same in various combinations. The first and last variants
// of |BindInterface()| here are sufficient for all use cases.
using BindInterfaceCallback =
base::OnceCallback<void(mojom::ConnectResult result,
const base::Optional<Identity>& identity)>;
template <typename Interface>
void BindInterface(const ServiceFilter& filter,
mojo::InterfaceRequest<Interface> request,
BindInterfaceCallback callback = {}) {
BindInterface(filter, Interface::Name_, request.PassMessagePipe(),
mojom::BindInterfacePriority::kImportant,
std::move(callback));
}
template <typename Interface>
void BindInterface(const ServiceFilter& filter,
mojo::InterfacePtr<Interface>* ptr) {
BindInterface(filter, mojo::MakeRequest(ptr));
}
template <typename Interface>
void BindInterface(const std::string& service_name,
mojo::InterfacePtr<Interface>* ptr) {
return BindInterface(ServiceFilter::ByName(service_name),
mojo::MakeRequest(ptr));
}
template <typename Interface>
void BindInterface(const std::string& service_name,
mojo::InterfaceRequest<Interface> request) {
return BindInterface(ServiceFilter::ByName(service_name),
std::move(request));
}
template <typename Interface>
void BindInterface(const ServiceFilter& filter,
mojo::InterfaceRequest<Interface> request,
mojom::BindInterfacePriority priority) {
return BindInterface(filter, Interface::Name_, request.PassMessagePipe(),
priority, {});
}
void BindInterface(const ServiceFilter& filter,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe,
BindInterfaceCallback callback = {}) {
BindInterface(filter, interface_name, std::move(interface_pipe),
mojom::BindInterfacePriority::kImportant,
std::move(callback));
}
void BindInterface(const ServiceFilter& filter,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe,
mojom::BindInterfacePriority priority,
BindInterfaceCallback callback);
// Creates a new instance of this class which may be passed to another thread.
// The returned object may be passed across sequences until any of its public
// methods are called, at which point it becomes bound to the calling
// sequence.
std::unique_ptr<Connector> Clone();
// Returns |true| if this Connector instance is already bound to a thread.
bool IsBound() const;
void FilterInterfaces(const std::string& spec,
const Identity& source_identity,
mojom::InterfaceProviderRequest request,
mojom::InterfaceProviderPtr target);
// Binds a Connector request to the other end of this Connector.
void BindConnectorRequest(mojom::ConnectorRequest request);
base::WeakPtr<Connector> GetWeakPtr();
// Test-only methods for interception of requests on Connectors. Consider
// using TestConnectorFactory to create and inject fake Connectors into
// production code instead of using these methods to monkey-patch existing
// Connector objects.
void OverrideBinderForTesting(const service_manager::ServiceFilter& filter,
const std::string& interface_name,
const TestApi::Binder& binder);
bool HasBinderOverrideForTesting(const service_manager::ServiceFilter& filter,
const std::string& interface_name);
void ClearBinderOverrideForTesting(
const service_manager::ServiceFilter& filter,
const std::string& interface_name);
void ClearBinderOverridesForTesting();
private:
using BinderOverrideMap = std::map<std::string, TestApi::Binder>;
void OnConnectionError();
bool BindConnectorIfNecessary();
mojom::ConnectorPtrInfo unbound_state_;
mojom::ConnectorPtr connector_;
SEQUENCE_CHECKER(sequence_checker_);
std::map<service_manager::ServiceFilter, BinderOverrideMap>
local_binder_overrides_;
base::WeakPtrFactory<Connector> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(Connector);
};
} // namespace service_manager
#endif // SERVICES_SERVICE_MANAGER_PUBLIC_CPP_CONNECTOR_H_