• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
InterfacePtr()47   InterfacePtr() {}
InterfacePtr(decltype (nullptr))48   InterfacePtr(decltype(nullptr)) {}
49 
50   // Takes over the binding of another InterfacePtr.
InterfacePtr(InterfacePtr && other)51   InterfacePtr(InterfacePtr&& other) noexcept {
52     internal_state_.Swap(&other.internal_state_);
53   }
54 
InterfacePtr(PtrInfoType && info)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.
decltype(nullptr)67   InterfacePtr& operator=(decltype(nullptr)) {
68     reset();
69     return *this;
70   }
71 
72   // Closes the bound message pipe (if any) on destruction.
~InterfacePtr()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.
is_bound()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.
get()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.
version()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.
QueryVersion(const base::Callback<void (uint32_t)> & callback)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.
RequireVersion(uint32_t version)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.
FlushForTesting()128   void FlushForTesting() { internal_state_.FlushForTesting(); }
129 
130   // Closes the bound message pipe, if any.
reset()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.
ResetWithReason(uint32_t custom_reason,const std::string & description)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.
HasAssociatedInterfaces()144   bool HasAssociatedInterfaces() const {
145     return internal_state_.HasAssociatedInterfaces();
146   }
147 
148   // Returns true if bound and awaiting a response to a message.
IsExpectingResponse()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).
encountered_error()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.
set_connection_error_handler(base::OnceClosure error_handler)161   void set_connection_error_handler(base::OnceClosure error_handler) {
162     internal_state_.set_connection_error_handler(std::move(error_handler));
163   }
164 
set_connection_error_with_reason_handler(ConnectionErrorWithReasonCallback error_handler)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.
PassInterface()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 
Equals(const InterfacePtr & other)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.
internal_state()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