Home | History | Annotate | Download | only in bindings
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_
      6 #define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_
      7 
      8 #include <stdint.h>
      9 
     10 #include <string>
     11 #include <utility>
     12 
     13 #include "base/callback_forward.h"
     14 #include "base/logging.h"
     15 #include "base/macros.h"
     16 #include "base/memory/ref_counted.h"
     17 #include "base/sequenced_task_runner.h"
     18 #include "mojo/public/cpp/bindings/connection_error_callback.h"
     19 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
     20 #include "mojo/public/cpp/bindings/lib/interface_ptr_state.h"
     21 
     22 namespace mojo {
     23 
     24 // A pointer to a local proxy of a remote Interface implementation. Uses a
     25 // message pipe to communicate with the remote implementation, and automatically
     26 // closes the pipe and deletes the proxy on destruction. The pointer must be
     27 // bound to a message pipe before the interface methods can be called. Once a
     28 // pointer is destroyed, it is guaranteed that pending callbacks as well as the
     29 // connection error handler (if registered) won't be called.
     30 //
     31 // This class is thread hostile, as is the local proxy it manages, while bound
     32 // to a message pipe. All calls to this class or the proxy should be from the
     33 // same sequence that bound it. If you need to move the proxy to a different
     34 // sequence, extract the InterfacePtrInfo (containing just the message pipe and
     35 // any version information) using PassInterface() on the original sequence, pass
     36 // it to a different sequence, and create and bind a new InterfacePtr from that
     37 // sequence. If an InterfacePtr is not bound to a message pipe, it may be bound
     38 // or destroyed on any sequence.
     39 template <typename Interface>
     40 class InterfacePtr {
     41  public:
     42   using InterfaceType = Interface;
     43   using PtrInfoType = InterfacePtrInfo<Interface>;
     44   using Proxy = typename Interface::Proxy_;
     45 
     46   // Constructs an unbound InterfacePtr.
     47   InterfacePtr() {}
     48   InterfacePtr(decltype(nullptr)) {}
     49 
     50   // Takes over the binding of another InterfacePtr.
     51   InterfacePtr(InterfacePtr&& other) noexcept {
     52     internal_state_.Swap(&other.internal_state_);
     53   }
     54 
     55   explicit InterfacePtr(PtrInfoType&& info) noexcept { Bind(std::move(info)); }
     56 
     57   // Takes over the binding of another InterfacePtr, and closes any message pipe
     58   // already bound to this pointer.
     59   InterfacePtr& operator=(InterfacePtr&& other) noexcept {
     60     reset();
     61     internal_state_.Swap(&other.internal_state_);
     62     return *this;
     63   }
     64 
     65   // Assigning nullptr to this class causes it to close the currently bound
     66   // message pipe (if any) and returns the pointer to the unbound state.
     67   InterfacePtr& operator=(decltype(nullptr)) {
     68     reset();
     69     return *this;
     70   }
     71 
     72   // Closes the bound message pipe (if any) on destruction.
     73   ~InterfacePtr() {}
     74 
     75   // Binds the InterfacePtr to a remote implementation of Interface.
     76   //
     77   // Calling with an invalid |info| (containing an invalid message pipe handle)
     78   // has the same effect as reset(). In this case, the InterfacePtr is not
     79   // considered as bound.
     80   //
     81   // Optionally, |runner| is a SequencedTaskRunner bound to the current sequence
     82   // on which all callbacks and connection error notifications will be
     83   // dispatched. It is only useful to specify this to use a different
     84   // SequencedTaskRunner than SequencedTaskRunnerHandle::Get().
     85   void Bind(InterfacePtrInfo<Interface> info,
     86             scoped_refptr<base::SequencedTaskRunner> runner = nullptr) {
     87     reset();
     88     if (info.is_valid())
     89       internal_state_.Bind(std::move(info), std::move(runner));
     90   }
     91 
     92   // Returns whether or not this InterfacePtr is bound to a message pipe.
     93   bool is_bound() const { return internal_state_.is_bound(); }
     94 
     95   // Returns a raw pointer to the local proxy. Caller does not take ownership.
     96   // Note that the local proxy is thread hostile, as stated above.
     97   Proxy* get() const { return internal_state_.instance(); }
     98 
     99   // Functions like a pointer to Interface. Must already be bound.
    100   Proxy* operator->() const { return get(); }
    101   Proxy& operator*() const { return *get(); }
    102 
    103   // Returns the version number of the interface that the remote side supports.
    104   uint32_t version() const { return internal_state_.version(); }
    105 
    106   // Queries the max version that the remote side supports. On completion, the
    107   // result will be returned as the input of |callback|. The version number of
    108   // this interface pointer will also be updated.
    109   void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
    110     internal_state_.QueryVersion(callback);
    111   }
    112 
    113   // If the remote side doesn't support the specified version, it will close its
    114   // end of the message pipe asynchronously. This does nothing if it's already
    115   // known that the remote side supports the specified version, i.e., if
    116   // |version <= this->version()|.
    117   //
    118   // After calling RequireVersion() with a version not supported by the remote
    119   // side, all subsequent calls to interface methods will be ignored.
    120   void RequireVersion(uint32_t version) {
    121     internal_state_.RequireVersion(version);
    122   }
    123 
    124   // Sends a no-op message on the underlying message pipe and runs the current
    125   // message loop until its response is received. This can be used in tests to
    126   // verify that no message was sent on a message pipe in response to some
    127   // stimulus.
    128   void FlushForTesting() { internal_state_.FlushForTesting(); }
    129 
    130   // Closes the bound message pipe, if any.
    131   void reset() {
    132     State doomed;
    133     internal_state_.Swap(&doomed);
    134   }
    135 
    136   // Similar to the method above, but also specifies a disconnect reason.
    137   void ResetWithReason(uint32_t custom_reason, const std::string& description) {
    138     if (internal_state_.is_bound())
    139       internal_state_.CloseWithReason(custom_reason, description);
    140     reset();
    141   }
    142 
    143   // Whether there are any associated interfaces running on the pipe currently.
    144   bool HasAssociatedInterfaces() const {
    145     return internal_state_.HasAssociatedInterfaces();
    146   }
    147 
    148   // Returns true if bound and awaiting a response to a message.
    149   bool IsExpectingResponse() { return internal_state_.has_pending_callbacks(); }
    150 
    151   // Indicates whether the message pipe has encountered an error. If true,
    152   // method calls made on this interface will be dropped (and may already have
    153   // been dropped).
    154   bool encountered_error() const { return internal_state_.encountered_error(); }
    155 
    156   // Registers a handler to receive error notifications. The handler will be
    157   // called from the sequence that owns this InterfacePtr.
    158   //
    159   // This method may only be called after the InterfacePtr has been bound to a
    160   // message pipe.
    161   void set_connection_error_handler(base::OnceClosure error_handler) {
    162     internal_state_.set_connection_error_handler(std::move(error_handler));
    163   }
    164 
    165   void set_connection_error_with_reason_handler(
    166       ConnectionErrorWithReasonCallback error_handler) {
    167     internal_state_.set_connection_error_with_reason_handler(
    168         std::move(error_handler));
    169   }
    170 
    171   // Unbinds the InterfacePtr and returns the information which could be used
    172   // to setup an InterfacePtr again. This method may be used to move the proxy
    173   // to a different sequence (see class comments for details).
    174   //
    175   // It is an error to call PassInterface() while:
    176   //   - there are pending responses; or
    177   //     TODO: fix this restriction, it's not always obvious when there is a
    178   //     pending response.
    179   //   - there are associated interfaces running.
    180   //     TODO(yzshen): For now, users need to make sure there is no one holding
    181   //     on to associated interface endpoint handles at both sides of the
    182   //     message pipe in order to call this method. We need a way to forcefully
    183   //     invalidate associated interface endpoint handles.
    184   InterfacePtrInfo<Interface> PassInterface() {
    185     CHECK(!HasAssociatedInterfaces());
    186     CHECK(!internal_state_.has_pending_callbacks());
    187     State state;
    188     internal_state_.Swap(&state);
    189 
    190     return state.PassInterface();
    191   }
    192 
    193   bool Equals(const InterfacePtr& other) const {
    194     if (this == &other)
    195       return true;
    196 
    197     // Now that the two refer to different objects, they are equivalent if
    198     // and only if they are both null.
    199     return !(*this) && !other;
    200   }
    201 
    202   // DO NOT USE. Exposed only for internal use and for testing.
    203   internal::InterfacePtrState<Interface>* internal_state() {
    204     return &internal_state_;
    205   }
    206 
    207   // Allow InterfacePtr<> to be used in boolean expressions.
    208   explicit operator bool() const { return internal_state_.is_bound(); }
    209 
    210  private:
    211   typedef internal::InterfacePtrState<Interface> State;
    212   mutable State internal_state_;
    213 
    214   DISALLOW_COPY_AND_ASSIGN(InterfacePtr);
    215 };
    216 
    217 // If |info| is valid (containing a valid message pipe handle), returns an
    218 // InterfacePtr bound to it. Otherwise, returns an unbound InterfacePtr.
    219 template <typename Interface>
    220 InterfacePtr<Interface> MakeProxy(
    221     InterfacePtrInfo<Interface> info,
    222     scoped_refptr<base::SequencedTaskRunner> runner = nullptr) {
    223   InterfacePtr<Interface> ptr;
    224   if (info.is_valid())
    225     ptr.Bind(std::move(info), std::move(runner));
    226   return std::move(ptr);
    227 }
    228 
    229 }  // namespace mojo
    230 
    231 #endif  // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_
    232