blob: 849bd03de318ec6ab3fb69c22c5ae234e2111435 [file]
// 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.
#ifndef MOJO_PUBLIC_CPP_BINDINGS_SHARED_ASSOCIATED_REMOTE_H_
#define MOJO_PUBLIC_CPP_BINDINGS_SHARED_ASSOCIATED_REMOTE_H_
#include "base/ignore_result.h"
#include "base/memory/ref_counted.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/shared_remote.h"
namespace mojo {
namespace internal {
template <typename Interface>
struct SharedRemoteTraits<AssociatedRemote<Interface>> {
static void BindDisconnected(AssociatedRemote<Interface>& remote) {
ignore_result(remote.BindNewEndpointAndPassDedicatedReceiver());
}
};
} // namespace internal
// SharedAssociatedRemote wraps a non-thread-safe AssociatedRemote and proxies
// messages to it. Unlike normal AssociatedRemote objects,
// SharedAssociatedRemote is copyable and usable from any thread, but has some
// additional overhead and latency in message transmission as a trade-off.
//
// Async calls are posted to the sequence that the underlying AssociatedRemote
// is bound to, and responses are posted back to the calling sequence. Sync
// calls are dispatched directly if the call is made on the sequence that the
// wrapped AssociatedRemote is bound to, or posted otherwise. It's important to
// be aware that sync calls block both the calling sequence and the bound
// AssociatedRemote's sequence. That means that you cannot make sync calls
// through a SharedAssociatedRemote if the underlying AssociatedRemote is bound
// to a sequence that cannot block, like the IPC thread.
template <typename Interface>
class SharedAssociatedRemote {
public:
SharedAssociatedRemote() = default;
explicit SharedAssociatedRemote(
PendingAssociatedRemote<Interface> pending_remote,
scoped_refptr<base::SequencedTaskRunner> bind_task_runner =
base::SequencedTaskRunnerHandle::Get()) {
if (pending_remote.is_valid())
Bind(std::move(pending_remote), std::move(bind_task_runner));
}
bool is_bound() const { return remote_ != nullptr; }
explicit operator bool() const { return is_bound(); }
Interface* get() const { return remote_->get(); }
Interface* operator->() const { return get(); }
Interface& operator*() const { return *get(); }
void set_disconnect_handler(
base::OnceClosure handler,
scoped_refptr<base::SequencedTaskRunner> handler_task_runner) {
remote_->set_disconnect_handler(std::move(handler),
std::move(handler_task_runner));
}
// Clears this SharedAssociatedRemote. Note that this does *not* necessarily
// close the remote's endpoint as other SharedAssociatedRemote instances may
// reference the same underlying endpoint.
void reset() { remote_.reset(); }
// Disconnects the SharedAssociatedRemote. This leaves the object in a usable
// state -- i.e. it's still safe to dereference and make calls -- but severs
// the underlying connection so that no new replies will be received and all
// outgoing messages will be discarded. This is useful when you want to force
// a disconnection like with reset(), but you don't want the
// SharedAssociatedRemote to become unbound.
void Disconnect() { remote_->Disconnect(); }
// Creates a new pair of endpoints and binds this SharedAssociatedRemote to
// one of them, on `task_runner`. The other is returned as a receiver.
mojo::PendingAssociatedReceiver<Interface> BindNewEndpointAndPassReceiver(
scoped_refptr<base::SequencedTaskRunner> bind_task_runner =
base::SequencedTaskRunnerHandle::Get()) {
mojo::PendingAssociatedRemote<Interface> remote;
auto receiver = remote.InitWithNewEndpointAndPassReceiver();
Bind(std::move(remote), std::move(bind_task_runner));
return receiver;
}
// Binds to `pending_remote` on `bind_task_runner`.
void Bind(PendingAssociatedRemote<Interface> pending_remote,
scoped_refptr<base::SequencedTaskRunner> bind_task_runner =
base::SequencedTaskRunnerHandle::Get()) {
DCHECK(!remote_);
DCHECK(pending_remote.is_valid());
remote_ = SharedRemoteBase<AssociatedRemote<Interface>>::Create(
std::move(pending_remote), std::move(bind_task_runner));
}
private:
scoped_refptr<SharedRemoteBase<AssociatedRemote<Interface>>> remote_;
};
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_SHARED_ASSOCIATED_REMOTE_H_