910e62b5创建于 1月15日历史提交
// Copyright 2019 The Chromium Authors
// 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_PENDING_REMOTE_H_
#define MOJO_PUBLIC_CPP_BINDINGS_PENDING_REMOTE_H_

#include <cstdint>
#include <type_traits>
#include <utility>

#include "base/check.h"
#include "base/compiler_specific.h"
#include "build/build_config.h"
#include "mojo/public/c/system/types.h"
#include "mojo/public/cpp/bindings/disconnect_reason.h"
#include "mojo/public/cpp/bindings/interface_id.h"
#include "mojo/public/cpp/bindings/lib/pending_remote_state.h"
#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
#include "mojo/public/cpp/bindings/runtime_features.h"
#include "mojo/public/cpp/system/message_pipe.h"

namespace mojo {

template <typename T>
class PendingReceiver;

template <typename T>
struct PendingRemoteConverter;

// A valid PendingRemote is entangled with exactly one Receiver or
// PendingReceiver, and can be consumed to bind a Remote in order to begin
// issuing method calls to that receiver. See Remote documentation for more
// details.
//
// PendingRemote instances may be freely moved to another thread/sequence, or
// even transferred to another process via a Mojo interface call (see
// pending_remote<T> syntax in mojom IDL).
//
// NOTE: This object is essentially semantic sugar wrapping a raw message pipe
// handle that is expected to send Interface messages of a specified version
// (typically 0) to a Receiver. As such, consumers who know what they're doing
// (i.e. who are confident about what lies on the other side of a pipe) may
// freely convert between a PendingRemote and a 2-tuple of
// [raw message pipe handle, expected interface version number].
template <typename Interface>
class PendingRemote {
 public:
  // Constructs an invalid PendingRemote. This object is not entangled with any
  // receiver and cannot be used to bind a Remote.
  //
  // A valid PendingRemote is typically obtained by calling
  // |Receiver::BindNewPipeAndPassRemote()| on an existing unbound Receiver
  // instance.
  //
  // To simultaneously create a valid PendingRemote and an entangled
  // PendingReceiver for rarer cases where both objects need to be passed
  // elsewhere, use the |InitWithNewPipeAndPassReceiver()| method defined below.
  PendingRemote() = default;
  PendingRemote(PendingRemote&&) noexcept = default;

  // Constructs a valid PendingRemote over a valid raw message pipe handle and
  // expected interface version number.
  PendingRemote(ScopedMessagePipeHandle pipe, uint32_t version)
      : state_(std::move(pipe), version) {}

  // Move conversion operator for custom remote types. Only participates in
  // overload resolution if a typesafe conversion is supported.
  template <typename T,
            std::enable_if_t<std::is_same<
                PendingRemote<Interface>,
                std::invoke_result_t<decltype(&PendingRemoteConverter<
                                              T>::template To<Interface>),
                                     T&&>>::value>* = nullptr>
  PendingRemote(T&& other)
      : PendingRemote(PendingRemoteConverter<T>::template To<Interface>(
            std::move(other))) {}

  PendingRemote(const PendingRemote&) = delete;
  PendingRemote& operator=(const PendingRemote&) = delete;

  ~PendingRemote() = default;

  PendingRemote& operator=(PendingRemote&&) noexcept = default;

  // Indicates whether the PendingRemote is valid, meaning it can be used to
  // bind a Remote that wants to begin issuing method calls to be dispatched by
  // the entangled Receiver.
  bool is_valid() const { return state_.pipe.is_valid(); }
  explicit operator bool() const { return is_valid(); }

  // Resets this PendingRemote to an invalid state. If it was entangled with a
  // Receiver or PendingReceiver, that object remains in a valid state and will
  // eventually detect that its remote caller is gone.
  void reset() { state_.reset(); }

  // Like above but provides a reason for the disconnection.
  void ResetWithReason(uint32_t reason, const std::string& description) {
    CHECK(is_valid()) << "Cannot send reset reason to an invalid handle.";

    Message message =
        PipeControlMessageProxy::ConstructPeerEndpointClosedMessage(
            kPrimaryInterfaceId, DisconnectReason(reason, description));
    MojoResult result =
        WriteMessageNew(state_.pipe.get(), message.TakeMojoMessage(),
                        MOJO_WRITE_MESSAGE_FLAG_NONE);
    DCHECK_EQ(MOJO_RESULT_OK, result);

    reset();
  }

  // Takes ownership of this PendingRemote's message pipe handle. After this
  // call, the PendingRemote is no longer in a valid state and can no longer be
  // used to bind a Remote.
  [[nodiscard]] ScopedMessagePipeHandle PassPipe() {
    state_.version = 0;
    return std::move(state_.pipe);
  }
  const ScopedMessagePipeHandle& Pipe() const { return state_.pipe; }

  // The version of the interface this Remote is assuming when making method
  // calls. For the most common case of unversioned mojom interfaces, this is
  // always zero.
  uint32_t version() const { return state_.version; }

  // Creates a new message pipe, retaining one end in the PendingRemote (making
  // it valid) and returning the other end as its entangled PendingReceiver. May
  // only be called on an invalid PendingRemote.
  [[nodiscard]] REINITIALIZES_AFTER_MOVE PendingReceiver<Interface>
  InitWithNewPipeAndPassReceiver();

  // For internal Mojo use only.
  internal::PendingRemoteState* internal_state() { return &state_; }

 private:
  internal::PendingRemoteState state_;
};

class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) NullRemote {
 public:
  template <typename Interface>
  operator PendingRemote<Interface>() const {
    return PendingRemote<Interface>();
  }
};

// Fuses a PendingReceiver<T> endpoint with a PendingRemote<T> endpoint. The
// endpoints must belong to two different message pipes, and this effectively
// fuses two pipes into a single pipe. Returns |true| on success or |false| on
// failure.
template <typename Interface>
bool FusePipes(PendingReceiver<Interface> receiver,
               PendingRemote<Interface> remote) {
  MojoResult result = FuseMessagePipes(receiver.PassPipe(), remote.PassPipe());
  return result == MOJO_RESULT_OK;
}

}  // namespace mojo

#include "mojo/public/cpp/bindings/pending_receiver.h"

namespace mojo {

template <typename Interface>
PendingReceiver<Interface>
PendingRemote<Interface>::InitWithNewPipeAndPassReceiver() {
  DCHECK(!is_valid()) << "PendingReceiver already has a remote";
  if (!internal::GetRuntimeFeature_ExpectEnabled<Interface>()) {
    return PendingReceiver<Interface>();
  }
  MessagePipe pipe;
  state_.pipe = std::move(pipe.handle0);
  return PendingReceiver<Interface>(std::move(pipe.handle1));
}

}  // namespace mojo

#endif  // MOJO_PUBLIC_CPP_BINDINGS_PENDING_REMOTE_H_