blob: 8bc25e090f0511df7934aab22dc6e1dcfe912363 [file] [log] [blame]
// 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_RECEIVER_H_
#define MOJO_PUBLIC_CPP_BINDINGS_RECEIVER_H_
#include <memory>
#include <utility>
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequenced_task_runner.h"
#include "mojo/public/cpp/bindings/connection_error_callback.h"
#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/bindings/lib/binding_state.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace mojo {
// A Receiver is used to receive and dispatch Interface method calls to a local
// implementation of Interface. Every Receiver object is permanently linked to
// an implementation of Interface at construction time. The Receiver begins
// receiving and scheduling method calls to the implementation once it becomes
// bound either by consuming a PendingReceiver (at construction time or via
// |Bind()|) or by calling |BindNewPipeAndPassRemote()|.
//
// Receiver is NOT thread- or sequence- safe and must be used from a single
// (but otherwise arbitrary) sequence. All bound Receiver objects are associated
// with a base::SequencedTaskRunner which the Receiver uses exclusively to
// schedule incoming method calls and disconnection notifications.
//
// IMPORTANT: In the name of memory safety, Interface method calls and
// disconnection notifications scheduled by a Receiver object will NEVER run
// beyond the lifetime of the Receiver object.
template <typename Interface,
typename ImplRefTraits = RawPtrImplRefTraits<Interface>>
class Receiver {
public:
// Typically (and by default) a Receiver uses a raw pointer to reference its
// linked Interface implementation object, because typically that
// implementation object owns the Receiver. An alternative |ImplRefTraits| may
// be provided as a second Receiver template argument in order to use a
// different reference type.
using ImplPointerType = typename ImplRefTraits::PointerType;
// Constructs an unbound Receiver linked to |impl| for the duration of the
// Receive's lifetime. The Receiver can be bound later by calling |Bind()| or
// |BindNewPipeAndPassRemote()|. An unbound Receiver does not schedule any
// asynchronous tasks.
explicit Receiver(ImplPointerType impl) : internal_state_(std::move(impl)) {}
// Constructs a bound Receiver by consuming |pending_receiver|. The Receiver
// is permanently linked to |impl| and will schedule incoming |impl| method
// and disconnection notifications on the default SequencedTaskRunner (i.e.
// base::SequencedTaskRunnerHandle::Get() at construction time).
Receiver(ImplPointerType impl, PendingReceiver<Interface> pending_receiver)
: Receiver(std::move(impl), std::move(pending_receiver), nullptr) {}
// Similar to above but the constructed Receiver schedules all tasks via
// |task_runner| instead of the default SequencedTaskRunner. |task_runner|
// must run tasks on the same sequence that owns this Receiver.
Receiver(ImplPointerType impl,
PendingReceiver<Interface> pending_receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner)
: internal_state_(std::move(impl)) {
Bind(std::move(pending_receiver), std::move(task_runner));
}
~Receiver() = default;
// Indicates whether this Receiver is bound, meaning it may continue to
// receive Interface method calls from a remote caller.
//
// NOTE: A Receiver is NEVER passively unbound. The only way for it to become
// unbound is to explicitly call |reset()| or |Unbind()|.
bool is_bound() const { return internal_state_.is_bound(); }
// Sets a OnceClosure to be invoked if this Receiver is cut off from its
// Remote (or PendingRemote). This can happen if the corresponding Remote (or
// unconsumed PendingRemote) has been destroyed, or if the Remote sends a
// malformed message. Must only be called on a bound Receiver object, and only
// remains set as long as the Receiver is both bound and connected.
//
// If ever invoked, |handler| will be scheduled asynchronously on the
// Receiver's bound SequencedTaskRunner.
void set_disconnect_handler(base::OnceClosure handler) {
internal_state_.set_connection_error_handler(std::move(handler));
}
// Like above but if this callback is set instead of the above, it can receive
// additional details about why the remote endpoint was closed, if provided.
void set_disconnect_with_reason_handler(
ConnectionErrorWithReasonCallback error_handler) {
DCHECK(is_bound());
internal_state_.set_connection_error_with_reason_handler(
std::move(error_handler));
}
// Resets this Receiver to an unbound state. An unbound Receiver will NEVER
// schedule method calls or disconnection notifications, and any pending tasks
// which were scheduled prior to unbinding are effectively cancelled.
void reset() { internal_state_.Close(); }
// Similar to the method above, but also specifies a disconnect reason.
void ResetWithReason(uint32_t custom_reason_code,
const std::string& description) {
internal_state_.CloseWithReason(custom_reason_code, description);
}
// Binds this Receiver, connecting it to a new PendingRemote which is
// returned for transmission elsewhere (typically to a Remote who will consume
// it to start making calls).
//
// The Receiver will schedule incoming |impl| method calls and disconnection
// notifications on the default SequencedTaskRunner (i.e.
// base::SequencedTaskRunnerHandle::Get() at the time of this call). Must only
// be called on an unbound Receiver.
PendingRemote<Interface> BindNewPipeAndPassRemote() WARN_UNUSED_RESULT {
return BindNewPipeAndPassRemote(nullptr);
}
// Like above, but the Receiver will schedule incoming |impl| method calls and
// disconnection notifications on |task_runner| rather than on the default
// SequencedTaskRunner. Must only be called on an unbound Receiver.
// |task_runner| must run tasks on the same sequence that owns this Receiver.
PendingRemote<Interface> BindNewPipeAndPassRemote(
scoped_refptr<base::SequencedTaskRunner> task_runner) WARN_UNUSED_RESULT {
DCHECK(!is_bound()) << "Receiver is already bound";
PendingRemote<Interface> remote;
Bind(remote.InitWithNewPipeAndPassReceiver(), std::move(task_runner));
return remote;
}
// Binds this Receiver by consuming |pending_receiver|, which must be valid.
// Must only be called on an unbound Receiver.
//
// The newly bound Receiver will schedule incoming |impl| method calls and
// disconnection notifications on the default SequencedTaskRunner (i.e.
// base::SequencedTaskRunnerHandle::Get() at the time of this call).
void Bind(PendingReceiver<Interface> pending_receiver) {
Bind(std::move(pending_receiver), nullptr);
}
// Like above, but the newly bound Receiver will schedule incoming |impl|
// method calls and disconnection notifications on |task_runner| instead of
// the default SequencedTaskRunner. Must only be called on an unbound
// Receiver. |task_runner| must run tasks on the same sequence that owns this
// Receiver.
void Bind(PendingReceiver<Interface> pending_receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
if (pending_receiver) {
internal_state_.Bind(pending_receiver.internal_state(),
std::move(task_runner));
} else {
reset();
}
}
// Unbinds this Receiver, preventing any further |impl| method calls or
// disconnection notifications from being scheduled by it. Any such tasks that
// were scheduled prior to unbinding are effectively cancelled.
//
// Returns a PendingReceiver which remains connected to this receiver's
// Remote and which may be transferred elsewhere and consumed by another
// Receiver. Any messages received but not actually dispatched by this
// Receiver remain intact within the returned PendingReceiver and can be
// dispatched by whomever binds with it later.
//
// Note that a Receiver should not be unbound while there are still living
// response callbacks that haven't been invoked, as once the Receiver is
// unbound those response callbacks are no longer valid and the Remote will
// never be able to receive its expected responses.
PendingReceiver<Interface> Unbind() WARN_UNUSED_RESULT {
CHECK(!internal_state_.HasAssociatedInterfaces());
return PendingReceiver<Interface>(
internal_state_.Unbind().PassMessagePipe());
}
// Sets the message filter to be notified of each incoming message before
// dispatch. If a filter returns |false| from Accept(), the message is not
// dispatched and the pipe is closed. Filters cannot be removed once added
// and only one can be set.
void SetFilter(std::unique_ptr<MessageFilter> filter) {
DCHECK(is_bound());
internal_state_.SetFilter(std::move(filter));
}
// Pause and resume message dispatch.
void Pause() {
CHECK(!internal_state_.HasAssociatedInterfaces());
internal_state_.PauseIncomingMethodCallProcessing();
}
void Resume() { internal_state_.ResumeIncomingMethodCallProcessing(); }
// Blocks the calling thread until a new message arrives and is dispatched
// to the bound implementation.
bool WaitForIncomingCall() {
return internal_state_.WaitForIncomingMethodCall(MOJO_DEADLINE_INDEFINITE);
}
// Flushes any replies previously sent by the Receiver, only unblocking once
// acknowledgement from the Remote is received.
void FlushForTesting() { internal_state_.FlushForTesting(); }
// Exposed for testing, should not generally be used.
void EnableTestingMode() { internal_state_.EnableTestingMode(); }
// Allows test code to swap the interface implementation.
ImplPointerType SwapImplForTesting(ImplPointerType new_impl) {
return internal_state_.SwapImplForTesting(new_impl);
}
// Reports the currently dispatching message as bad and resets this receiver.
// Note that this is only legal to call from within the stack frame of a
// message dispatch. If you need to do asynchronous work before determining
// the legitimacy of a message, use GetBadMessageCallback() and retain its
// result until ready to invoke or discard it.
void ReportBadMessage(const std::string& error) {
GetBadMessageCallback().Run(error);
}
// Acquires a callback which may be run to report the currently dispatching
// message as bad and reset this receiver. Note that this is only legal to
// call from directly within stack frame of a message dispatch, but the
// returned callback may be called exactly once any time thereafter to report
// the message as bad. |GetBadMessageCallback()| may only be called once per
// message, and the returned callback must be run on the same sequence to
// which this Receiver is bound.
ReportBadMessageCallback GetBadMessageCallback() {
return internal_state_.GetBadMessageCallback();
}
// DO NOT USE. Exposed only for internal use and for testing.
internal::BindingState<Interface, ImplRefTraits>* internal_state() {
return &internal_state_;
}
private:
internal::BindingState<Interface, ImplRefTraits> internal_state_;
DISALLOW_COPY_AND_ASSIGN(Receiver);
};
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_RECEIVER_H_