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