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