text: // 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_REMOTE_H_
  #define MOJO_PUBLIC_CPP_BINDINGS_REMOTE_H_
  
  #include <cstdint>
  #include <utility>
  
  #include "base/callback_forward.h"
  #include "base/check.h"
  #include "base/compiler_specific.h"
  #include "base/macros.h"
  #include "base/memory/scoped_refptr.h"
  #include "base/sequenced_task_runner.h"
  #include "base/time/time.h"
  #include "mojo/public/cpp/bindings/async_flusher.h"
  #include "mojo/public/cpp/bindings/interface_ptr_info.h"
  #include "mojo/public/cpp/bindings/lib/interface_ptr_state.h"
  #include "mojo/public/cpp/bindings/pending_flush.h"
  #include "mojo/public/cpp/bindings/pending_remote.h"
  #include "mojo/public/cpp/bindings/receiver.h"
  #include "mojo/public/cpp/system/message_pipe.h"
  
  namespace mojo {
  
  // A Remote is used to issue Interface method calls to a single connected
  // Receiver or PendingReceiver. The Remote must be bound in order to issue those
  // method calls, and it becomes bound by consuming a PendingRemote either at
  // construction time or by calling |Bind()|.
  //
  // Remote is NOT thread- or sequence-safe and must be used on a single
  // (but otherwise arbitrary) sequence. All bound Remote objects are associated
  // with a base::SequenceTaskRunner which the Remote uses exclusively to schedule
  // response callbacks and disconnection notifications.
  //
  // The most common ways to bind a Remote are to consume a PendingRemote received
  // via some IPC, or to call |BindNewPipeAndPassReceiver()| and send the returned
  // PendingReceiver somewhere useful (i.e., to a remote Receiver who will consume
  // it). For example:
  //
  //     mojo::Remote<mojom::Widget> widget;
  //     widget_factory->CreateWidget(widget.BindNewPipeAndPassReceiver());
  //     widget->Click();
  //
  // IMPORTANT: There are some things to be aware of regarding Interface method
  // calls as they relate to Remote object lifetime:
  //
  //   - Interface method calls issued immediately before the destruction of a
  //     Remote ARE guaranteed to be transmitted to the remote's receiver as long
  //     as the receiver itself remains alive, either as a Receiver or a
  //     PendingReceiver.
  //
  //   - In the name of memory safety, Interface method response callbacks (and in
  //     general ANY tasks which can be scheduled by a Remote) will NEVER
  //     be dispatched beyond the lifetime of the Remote object. As such, if
  //     you make a call and you need its reply, you must keep the Remote alive
  //     until the reply is received.
  template <typename Interface>
  class Remote {
   public:
    using InterfaceType = Interface;
    using PendingType = PendingRemote<Interface>;
  
    // Constructs an unbound Remote. This object cannot issue Interface method
    // calls and does not schedule any tasks.
    Remote() = default;
    Remote(Remote&& other) noexcept { *this = std::move(other); }
  
    // Constructs a new Remote which is bound from |pending_remote| and which
    // schedules response callbacks and disconnection notifications on the default
    // SequencedTaskRunner (i.e., base::SequencedTaskRunnerHandle::Get() at
    // construction time).
    explicit Remote(PendingRemote<Interface> pending_remote)
        : Remote(std::move(pending_remote), nullptr) {}
  
    // Constructs a new Remote which is bound from |pending_remote| and which
    // schedules response callbacks and disconnection notifications on
    // |task_runner|. |task_runner| must run tasks on the same sequence that owns
    // this Remote.
    Remote(PendingRemote<Interface> pending_remote,
           scoped_refptr<base::SequencedTaskRunner> task_runner) {
      Bind(std::move(pending_remote), std::move(task_runner));
    }
  
    ~Remote() = default;
  
    Remote& operator=(Remote&& other) noexcept {
      internal_state_.Swap(&other.internal_state_);
      return *this;
    }
  
    // Exposes access to callable Interface methods directed at this Remote's
    // receiver. Must only be called on a bound Remote.
    typename Interface::Proxy_* get() const {
      DCHECK(is_bound())
          << "Cannot issue Interface method calls on an unbound Remote";
      return internal_state_.instance();
    }
  
    // Shorthand form of |get()|. See above.
    typename Interface::Proxy_* operator->() const { return get(); }
    typename Interface::Proxy_& operator*() const { return *get(); }
  
    // Indicates whether this Remote is bound and thus can issue Interface method
    // calls via the above accessors.
    //
    // NOTE: The state of being "bound" should not be confused with the state of
    // being "connected" (see |is_connected()| below). A Remote is NEVER passively
    // unbound and the only way for it to become unbound is to explicitly call
    // |reset()| or |Unbind()|. As such, unless you make explicit calls to those
    // methods, it is always safe to assume that a Remote you've bound will remain
    // bound and callable.
    bool is_bound() const { return internal_state_.is_bound(); }
    explicit operator bool() const { return is_bound(); }
  
    // Indicates whether this Remote is connected to a receiver. Must only be
    // called on a bound Remote. If this returns |true|, method calls made by this
    // Remote may eventually end up at the connected receiver (though it's of
    // course possible for this call to race with disconnection). If this returns
    // |false| however, all future Interface method calls on this Remote will be
    // silently dropped.
    //
    // A bound Remote becomes disconnected automatically either when its receiver
    // is destroyed, or when it receives a malformed or otherwise unexpected
    // response message from the receiver.
    //
    // NOTE: The state of being "bound" should not be confused with the state of
    // being "connected". See |is_bound()| above.
    bool is_connected() const {
      DCHECK(is_bound());
      return !internal_state_.encountered_error();
    }
  
    // Sets a Closure to be invoked if this Remote is cut off from its receiver.
    // This can happen if the corresponding Receiver (or unconsumed
    // PendingReceiver) is destroyed, or if the Receiver sends a malformed or
    // otherwise unexpected response message to this Remote. Must only be called
    // on a bound Remote object, and only remains set as long as the Remote is
    // both bound and connected.
    //
    // If invoked at all, |handler| will be scheduled asynchronously using the
    // Remote's bound SequencedTaskRunner.
    void set_disconnect_handler(base::OnceClosure handler) {
      if (is_connected())
        internal_state_.set_connection_error_handler(std::move(handler));
    }
  
    // Like above but also receives extra user-defined metadata about why the
    // receiving endpoint was closed.
    void set_disconnect_with_reason_handler(
        ConnectionErrorWithReasonCallback handler) {
      internal_state_.set_connection_error_with_reason_handler(
          std::move(handler));
    }
  
    // A convenient helper that resets this Remote on disconnect. Note that this
    // replaces any previously set disconnection handler.
    void reset_on_disconnect() {
      if (!is_connected()) {
        reset();
        return;
      }
      set_disconnect_handler(
          base::BindOnce(&Remote::reset, base::Unretained(this)));
    }
  
    // Sets a Closure to be invoked any time the receiving endpoint reports itself
    // as idle and there are no in-flight messages it has yet to acknowledge, and
    // this state occurs continuously for a duration of at least |timeout|. The
    // first time this is called, it must be called BEFORE sending any interface
    // messages to the receiver. It may be called any number of times after that
    // to reconfigure the idle timeout period or assign a new idle handler.
    //
    // Once called, the interface connection incurs some permanent additional
    // per-message overhead to help track idle state across the interface
    // boundary.
    //
    // Whenever this callback is invoked, the following conditions are guaranteed
    // to hold:
    //
    //   - There are no messages sent on this Remote that have not already been
    //     dispatched by the receiver.
    //   - There are no interfaces which were bound directly or transitively
    //     through this Remote and are still connected.
    //   - The receiver has explicitly notified us that it considers itself to be
    //     "idle."
    //   - The receiver has not dispatched any additional messages since sending
    //     this idle notification.
    //   - The Remote does not have any outstanding reply callbacks that haven't
    //     been called yet.
    //   - All of the above has been true continuously for a duration of at least
    //     |timeout|.
    //
    void set_idle_handler(base::TimeDelta timeout,
                          base::RepeatingClosure handler) {
      internal_state_.set_idle_handler(timeout, std::move(handler));
    }
  
    // A convenient helper for common idle timeout behavior. This is equivalent to
    // calling |set_idle_handler| with a handler that only resets this Remote.
    void reset_on_idle_timeout(base::TimeDelta timeout) {
      set_idle_handler(
          timeout, base::BindRepeating(&Remote::reset, base::Unretained(this)));
    }
  
    // Resets this Remote to an unbound state. To reset the Remote and recover an
    // PendingRemote that can be bound again later, use |Unbind()| instead.
    void reset() {
      State doomed_state;
      internal_state_.Swap(&doomed_state);
    }
  
    // Similar to the method above, but also specifies a disconnect reason.
    void ResetWithReason(uint32_t custom_reason, const std::string& description) {
      if (internal_state_.is_bound())
        internal_state_.CloseWithReason(custom_reason, description);
      reset();
    }
  
    // Returns the version of Interface used by this Remote. Defaults to 0 but can
    // be adjusted either at binding time, or by invoking either |QueryVersion()|
    // or |RequireVersion()|.
    uint32_t version() const { return internal_state_.version(); }
  
    // Binds this Remote, connecting it to a new PendingReceiver which is
    // returned for transmission to some Receiver which can bind it. The Remote
    // will schedule any response callbacks or disconnection notifications on the
    // default SequencedTaskRunner (i.e. base::SequencedTaskRunnerHandle::Get() at
    // the time of this call). Must only be called on an unbound Remote.
    PendingReceiver<Interface> BindNewPipeAndPassReceiver() WARN_UNUSED_RESULT {
      DCHECK(!is_bound()) << "Remote is already bound";
      return BindNewPipeAndPassReceiver(nullptr);
    }
  
    // Like above, but the Remote will schedule response callbacks and
    // disconnection notifications on |task_runner| instead of the default
    // SequencedTaskRunner. |task_runner| must run tasks on the same sequence that
    // owns this Remote.
    PendingReceiver<Interface> BindNewPipeAndPassReceiver(
        scoped_refptr<base::SequencedTaskRunner> task_runner) WARN_UNUSED_RESULT {
      DCHECK(!is_bound()) << "Remote is already bound";
      MessagePipe pipe;
      Bind(PendingRemote<Interface>(std::move(pipe.handle0), 0),
           std::move(task_runner));
      return PendingReceiver<Interface>(std::move(pipe.handle1));
    }
  
    // Binds this Remote by consuming |pending_remote|, which must be valid. The
    // Remote will schedule any response callbacks or disconnection notifications
    // on the default SequencedTaskRunner (i.e.
    // base::SequencedTaskRunnerHandle::Get() at the time of this call). Must only
    // be called on an unbound Remote.
    void Bind(PendingRemote<Interface> pending_remote) {
      DCHECK(!is_bound()) << "Remote is already bound";
      DCHECK(pending_remote.is_valid());
      Bind(std::move(pending_remote), nullptr);
    }
  
    // Like above, but the Remote will schedule response callbacks and
    // disconnection notifications on |task_runner| instead of the default
    // SequencedTaskRunner. Must only be called on an unbound Remote.
    // |task_runner| must run tasks on the same sequence that owns this Remote.
    void Bind(PendingRemote<Interface> pending_remote,
              scoped_refptr<base::SequencedTaskRunner> task_runner) {
      DCHECK(!is_bound()) << "Remote is already bound";
      if (!pending_remote) {
        reset();
        return;
      }
  
      internal_state_.Bind(pending_remote.internal_state(),
                           std::move(task_runner));
  
      // Force the internal state to configure its proxy. Unlike InterfacePtr we
      // do not use Remote in transit, so binding to a pipe handle can also imply
      // binding to a SequencedTaskRunner and observing pipe handle state. This
      // allows for e.g. |is_connected()| to be a more reliable API than
      // |InterfacePtr::encountered_error()|.
      ignore_result(internal_state_.instance());
    }
  
    // Unbinds this Remote, rendering it unable to issue further Interface method
    // calls. Returns a PendingRemote which may be passed across threads or
    // processes and consumed by another Remote elsewhere.
    //
    // Note that it is an error (the bad, crashy kind of error) to attempt to
    // |Unbind()| a Remote which is awaiting one or more responses to previously
    // issued Interface method calls. Calling this method should only be
    // considered in cases where satisfaction of that constraint can be proven.
    //
    // Must only be called on a bound Remote.
    PendingRemote<Interface> Unbind() WARN_UNUSED_RESULT {
      DCHECK(is_bound());
      CHECK(!internal_state_.has_pending_callbacks());
      State state;
      internal_state_.Swap(&state);
      InterfacePtrInfo<Interface> info = state.PassInterface();
      return PendingRemote<Interface>(info.PassHandle(), info.version());
    }
  
    // Queries the max version that the receiving endpoint supports. Once a
    // response is received, |callback| will be invoked with the version number
    // and the version number of this Remote object will also be updated.
    void QueryVersion(base::OnceCallback<void(uint32_t)> callback) {
      internal_state_.QueryVersion(std::move(callback));
    }
  
    // Requires the receiving endpoint to support at least the specified
    // |version|. If it does not, it will close its end of the connection
    // immediately.
    void RequireVersion(uint32_t version) {
      internal_state_.RequireVersion(version);
    }
  
    // Pauses the receiving endpoint until the flush corresponding to |flush| has
    // completed. Any calls made on this Remote prior to this call will be
    // dispatched at the receiving endpoint before pausing. The endpoint will not
    // dispatch any subsequent calls until the flush operation corresponding to
    // |flush| has been completed or canceled.
    //
    // See documentation for |FlushAsync()| on Remote and Receiver for how to
    // acquire a PendingFlush object, and documentation on PendingFlush for
    // example usage.
    void PauseReceiverUntilFlushCompletes(PendingFlush flush) {
      internal_state_.PauseReceiverUntilFlushCompletes(std::move(flush));
    }
  
    // Flushes the receiving endpoint asynchronously using |flusher|. Once all
    // calls made on this Remote prior to this |FlushAsyncWithFlusher()| call have
    // dispatched at the receiving endpoint, |flusher| will signal its
    // corresponding PendingFlush, unblocking any endpoint waiting on the flush
    // operation.
    //
    // NOTE: It is more common to use |FlushAsync()| defined below. If you really
    // want to provide your own AsyncFlusher using this method, see the
    // single-arugment constructor on PendingFlush. This would typically be used
    // when code executing on the current sequence wishes to immediately pause
    // one of its remote endpoints to wait on a flush operation that needs to be
    // initiated on a separate sequence. Rather than bouncing to the second
    // sequence to initiate a flush and then passing a PendingFlush back to the
    // original sequence, the AsyncFlusher/PendingFlush can be created on the
    // original sequence and a single task can be posted to pass the AsyncFlusher
    // to the second sequence for use with this method.
    void FlushAsyncWithFlusher(AsyncFlusher flusher) {
      internal_state_.FlushAsync(std::move(flusher));
    }
  
    // Same as above but an AsyncFlusher/PendingFlush pair is created on the
    // caller's behalf. The AsyncFlusher is immediately passed to a
    // |FlushAsyncWithFlusher()| call on this object, while the PendingFlush is
    // returned for use by the caller. See documentation on PendingFlush for
    // example usage.
    PendingFlush FlushAsync() {
      AsyncFlusher flusher;
      PendingFlush flush(&flusher);
      FlushAsyncWithFlusher(std::move(flusher));
      return flush;
    }
  
    // Sends a no-op message on the underlying message pipe and runs the current
    // message loop until its response is received. This can be used in tests to
    // verify that no message was sent on a message pipe in response to some
    // stimulus.
    void FlushForTesting() { internal_state_.FlushForTesting(); }
  
    // Same as |FlushForTesting()| but will call |callback| when the flush is
    // complete.
    void FlushAsyncForTesting(base::OnceClosure callback) {
      internal_state_.FlushAsyncForTesting(std::move(callback));
    }
  
    // Returns the number of unacknowledged messages sent by this Remote. Only
    // non-zero when |set_idle_handler()| has been called.
    unsigned int GetNumUnackedMessagesForTesting() const {
      return internal_state_.GetNumUnackedMessagesForTesting();
    }
  
    // DO NOT USE. Exposed only for internal use and for testing.
    internal::InterfacePtrState<Interface>* internal_state() {
      return &internal_state_;
    }
  
   private:
    using State = internal::InterfacePtrState<Interface>;
    mutable State internal_state_;
  
    DISALLOW_COPY_AND_ASSIGN(Remote);
  };
  
  }  // namespace mojo
  
  #endif  // MOJO_PUBLIC_CPP_BINDINGS_REMOTE_H_
  