#include "mojo/public/cpp/bindings/service_factory.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
namespace mojo {
ServiceFactory::ServiceFactory() = default;
ServiceFactory::~ServiceFactory() = default;
bool ServiceFactory::CanRunService(
const GenericPendingReceiver& receiver) const {
DCHECK(receiver.is_valid());
return base::Contains(constructors_, *receiver.interface_name());
}
bool ServiceFactory::RunService(GenericPendingReceiver receiver,
base::OnceClosure termination_callback) {
DCHECK(receiver.is_valid());
MessagePipeHandle pipe = receiver.pipe();
auto it = constructors_.find(*receiver.interface_name());
if (it == constructors_.end())
return false;
auto instance = it->second.Run(std::move(receiver));
if (!instance)
return false;
auto disconnect_callback =
base::BindOnce(&ServiceFactory::OnInstanceDisconnected,
weak_ptr_factory_.GetWeakPtr(), instance.get());
if (termination_callback) {
disconnect_callback =
std::move(disconnect_callback).Then(std::move(termination_callback));
}
instance->WatchPipe(pipe, std::move(disconnect_callback));
instances_.insert(std::move(instance));
return true;
}
void ServiceFactory::OnInstanceDisconnected(InstanceHolderBase* instance) {
instances_.erase(instance);
}
ServiceFactory::InstanceHolderBase::InstanceHolderBase()
: watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC) {}
ServiceFactory::InstanceHolderBase::~InstanceHolderBase() = default;
void ServiceFactory::InstanceHolderBase::WatchPipe(
MessagePipeHandle pipe,
base::OnceClosure disconnect_callback) {
DCHECK(!disconnect_callback_);
disconnect_callback_ = std::move(disconnect_callback);
watcher_.Watch(pipe, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
base::BindRepeating(&InstanceHolderBase::OnPipeSignaled,
base::Unretained(this)));
}
void ServiceFactory::InstanceHolderBase::OnPipeSignaled(
MojoResult result,
const HandleSignalsState& state) {
if (result == MOJO_RESULT_FAILED_PRECONDITION ||
result == MOJO_RESULT_CANCELLED) {
watcher_.Cancel();
DCHECK(disconnect_callback_);
std::move(disconnect_callback_).Run();
}
}
}