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