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