• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 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_ASSOCIATED_INTERFACE_PTR_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
7 
8 #include <stdint.h>
9 #include <utility>
10 
11 #include "base/callback.h"
12 #include "base/logging.h"
13 #include "base/macros.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "mojo/public/cpp/bindings/associated_group.h"
18 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
19 #include "mojo/public/cpp/bindings/associated_interface_request.h"
20 #include "mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h"
21 
22 namespace mojo {
23 
24 // Represents the client side of an associated interface. It is similar to
25 // InterfacePtr, except that it doesn't own a message pipe handle.
26 template <typename Interface>
27 class AssociatedInterfacePtr {
28  public:
29   // Constructs an unbound AssociatedInterfacePtr.
AssociatedInterfacePtr()30   AssociatedInterfacePtr() {}
AssociatedInterfacePtr(decltype (nullptr))31   AssociatedInterfacePtr(decltype(nullptr)) {}
32 
AssociatedInterfacePtr(AssociatedInterfacePtr && other)33   AssociatedInterfacePtr(AssociatedInterfacePtr&& other) {
34     internal_state_.Swap(&other.internal_state_);
35   }
36 
37   AssociatedInterfacePtr& operator=(AssociatedInterfacePtr&& other) {
38     reset();
39     internal_state_.Swap(&other.internal_state_);
40     return *this;
41   }
42 
43   // Assigning nullptr to this class causes it to closes the associated
44   // interface (if any) and returns the pointer to the unbound state.
decltype(nullptr)45   AssociatedInterfacePtr& operator=(decltype(nullptr)) {
46     reset();
47     return *this;
48   }
49 
~AssociatedInterfacePtr()50   ~AssociatedInterfacePtr() {}
51 
52   // Sets up this object as the client side of an associated interface.
53   // Calling with an invalid |info| has the same effect as reset(). In this
54   // case, the AssociatedInterfacePtr is not considered as bound.
55   //
56   // |runner| must belong to the same thread. It will be used to dispatch all
57   // callbacks and connection error notification. It is useful when you attach
58   // multiple task runners to a single thread for the purposes of task
59   // scheduling.
60   //
61   // NOTE: Please see the comments of
62   // AssociatedGroup.CreateAssociatedInterface() about when you can use this
63   // object to make calls.
64   void Bind(AssociatedInterfacePtrInfo<Interface> info,
65             scoped_refptr<base::SingleThreadTaskRunner> runner =
66                 base::ThreadTaskRunnerHandle::Get()) {
67     reset();
68 
69     bool is_local = info.handle().is_local();
70 
71     DCHECK(is_local) << "The AssociatedInterfacePtrInfo is supposed to be used "
72                         "at the other side of the message pipe.";
73 
74     if (info.is_valid() && is_local)
75       internal_state_.Bind(std::move(info), std::move(runner));
76   }
77 
is_bound()78   bool is_bound() const { return internal_state_.is_bound(); }
79 
get()80   Interface* get() const { return internal_state_.instance(); }
81 
82   // Functions like a pointer to Interface. Must already be bound.
83   Interface* operator->() const { return get(); }
84   Interface& operator*() const { return *get(); }
85 
86   // Returns the version number of the interface that the remote side supports.
version()87   uint32_t version() const { return internal_state_.version(); }
88 
89   // Returns the internal interface ID of this associated interface.
interface_id()90   uint32_t interface_id() const { return internal_state_.interface_id(); }
91 
92   // Queries the max version that the remote side supports. On completion, the
93   // result will be returned as the input of |callback|. The version number of
94   // this object will also be updated.
QueryVersion(const base::Callback<void (uint32_t)> & callback)95   void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
96     internal_state_.QueryVersion(callback);
97   }
98 
99   // If the remote side doesn't support the specified version, it will close the
100   // associated interface asynchronously. This does nothing if it's already
101   // known that the remote side supports the specified version, i.e., if
102   // |version <= this->version()|.
103   //
104   // After calling RequireVersion() with a version not supported by the remote
105   // side, all subsequent calls to interface methods will be ignored.
RequireVersion(uint32_t version)106   void RequireVersion(uint32_t version) {
107     internal_state_.RequireVersion(version);
108   }
109 
110   // Closes the associated interface (if any) and returns the pointer to the
111   // unbound state.
reset()112   void reset() {
113     State doomed;
114     internal_state_.Swap(&doomed);
115   }
116 
117   // Indicates whether an error has been encountered. If true, method calls made
118   // on this interface will be dropped (and may already have been dropped).
encountered_error()119   bool encountered_error() const { return internal_state_.encountered_error(); }
120 
121   // Registers a handler to receive error notifications.
122   //
123   // This method may only be called after the AssociatedInterfacePtr has been
124   // bound.
set_connection_error_handler(const base::Closure & error_handler)125   void set_connection_error_handler(const base::Closure& error_handler) {
126     internal_state_.set_connection_error_handler(error_handler);
127   }
128 
129   // Unbinds and returns the associated interface pointer information which
130   // could be used to setup an AssociatedInterfacePtr again. This method may be
131   // used to move the proxy to a different thread.
132   //
133   // It is an error to call PassInterface() while there are pending responses.
134   // TODO: fix this restriction, it's not always obvious when there is a
135   // pending response.
PassInterface()136   AssociatedInterfacePtrInfo<Interface> PassInterface() {
137     DCHECK(!internal_state_.has_pending_callbacks());
138     State state;
139     internal_state_.Swap(&state);
140 
141     return state.PassInterface();
142   }
143 
144   // Returns the associated group that this object belongs to. Returns null if
145   // the object is not bound.
associated_group()146   AssociatedGroup* associated_group() {
147     return internal_state_.associated_group();
148   }
149 
150   // DO NOT USE. Exposed only for internal use and for testing.
internal_state()151   internal::AssociatedInterfacePtrState<Interface>* internal_state() {
152     return &internal_state_;
153   }
154 
155   // Allow AssociatedInterfacePtr<> to be used in boolean expressions, but not
156   // implicitly convertible to a real bool (which is dangerous).
157  private:
158   // TODO(dcheng): Use an explicit conversion operator.
159   typedef internal::AssociatedInterfacePtrState<Interface>
160       AssociatedInterfacePtr::*Testable;
161 
162  public:
Testable()163   operator Testable() const {
164     return internal_state_.is_bound() ? &AssociatedInterfacePtr::internal_state_
165                                       : nullptr;
166   }
167 
168  private:
169   // Forbid the == and != operators explicitly, otherwise AssociatedInterfacePtr
170   // will be converted to Testable to do == or != comparison.
171   template <typename T>
172   bool operator==(const AssociatedInterfacePtr<T>& other) const = delete;
173   template <typename T>
174   bool operator!=(const AssociatedInterfacePtr<T>& other) const = delete;
175 
176   typedef internal::AssociatedInterfacePtrState<Interface> State;
177   mutable State internal_state_;
178 
179   DISALLOW_COPY_AND_ASSIGN(AssociatedInterfacePtr);
180 };
181 
182 // Creates an associated interface. The output |ptr| should be used locally
183 // while the returned request should be passed through the message pipe endpoint
184 // referred to by |associated_group| to setup the corresponding asssociated
185 // interface implementation at the remote side.
186 //
187 // NOTE: |ptr| should NOT be used to make calls before the request is sent.
188 // Violating that will cause the message pipe to be closed. On the other hand,
189 // as soon as the request is sent, |ptr| is usable. There is no need to wait
190 // until the request is bound to an implementation at the remote side.
191 template <typename Interface>
192 AssociatedInterfaceRequest<Interface> GetProxy(
193     AssociatedInterfacePtr<Interface>* ptr,
194     AssociatedGroup* group,
195     scoped_refptr<base::SingleThreadTaskRunner> runner =
196         base::ThreadTaskRunnerHandle::Get()) {
197   AssociatedInterfaceRequest<Interface> request;
198   AssociatedInterfacePtrInfo<Interface> ptr_info;
199   group->CreateAssociatedInterface(AssociatedGroup::WILL_PASS_REQUEST,
200                                    &ptr_info, &request);
201 
202   ptr->Bind(std::move(ptr_info), std::move(runner));
203   return request;
204 }
205 
206 }  // namespace mojo
207 
208 #endif  // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
209