| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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 THIRD_PARTY_MOJO_SRC_MOJO_EDK_SYSTEM_CHANNEL_H_ | |
| 6 #define THIRD_PARTY_MOJO_SRC_MOJO_EDK_SYSTEM_CHANNEL_H_ | |
| 7 | |
| 8 #include <stdint.h> | |
| 9 | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/containers/hash_tables.h" | |
| 13 #include "base/memory/ref_counted.h" | |
| 14 #include "base/memory/scoped_ptr.h" | |
| 15 #include "base/threading/thread_checker.h" | |
| 16 #include "mojo/public/c/system/types.h" | |
| 17 #include "mojo/public/cpp/system/macros.h" | |
| 18 #include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h" | |
| 19 #include "third_party/mojo/src/mojo/edk/system/channel_endpoint.h" | |
| 20 #include "third_party/mojo/src/mojo/edk/system/channel_endpoint_id.h" | |
| 21 #include "third_party/mojo/src/mojo/edk/system/incoming_endpoint.h" | |
| 22 #include "third_party/mojo/src/mojo/edk/system/message_in_transit.h" | |
| 23 #include "third_party/mojo/src/mojo/edk/system/mutex.h" | |
| 24 #include "third_party/mojo/src/mojo/edk/system/raw_channel.h" | |
| 25 #include "third_party/mojo/src/mojo/edk/system/system_impl_export.h" | |
| 26 | |
| 27 namespace mojo { | |
| 28 | |
| 29 namespace embedder { | |
| 30 class PlatformSupport; | |
| 31 } | |
| 32 | |
| 33 namespace system { | |
| 34 | |
| 35 class ChannelEndpointClient; | |
| 36 class ChannelManager; | |
| 37 class MessageInTransitQueue; | |
| 38 | |
| 39 // This class is mostly thread-safe. It must be created on an I/O thread. | |
| 40 // |Init()| must be called on that same thread before it becomes thread-safe (in | |
| 41 // particular, before references are given to any other thread) and |Shutdown()| | |
| 42 // must be called on that same thread before destruction. Its public methods are | |
| 43 // otherwise thread-safe. (Many private methods are restricted to the creation | |
| 44 // thread.) It may be destroyed on any thread, in the sense that the last | |
| 45 // reference to it may be released on any thread, with the proviso that | |
| 46 // |Shutdown()| must have been called first (so the pattern is that a "main" | |
| 47 // reference is kept on its creation thread and is released after |Shutdown()| | |
| 48 // is called, but other threads may have temporarily "dangling" references). | |
| 49 // | |
| 50 // Note the lock order (in order of allowable acquisition): | |
| 51 // |ChannelEndpointClient| (e.g., |MessagePipe|), |ChannelEndpoint|, |Channel|. | |
| 52 // Thus |Channel| may not call into |ChannelEndpoint| with |Channel|'s lock | |
| 53 // held. | |
| 54 class MOJO_SYSTEM_IMPL_EXPORT Channel final | |
| 55 : public base::RefCountedThreadSafe<Channel>, | |
| 56 public RawChannel::Delegate { | |
| 57 public: | |
| 58 // |platform_support| must remain alive until after |Shutdown()| is called. | |
| 59 explicit Channel(embedder::PlatformSupport* platform_support); | |
| 60 | |
| 61 // This must be called on the creation thread before any other methods are | |
| 62 // called, and before references to this object are given to any other | |
| 63 // threads. |raw_channel| should be uninitialized. | |
| 64 void Init(scoped_ptr<RawChannel> raw_channel) MOJO_NOT_THREAD_SAFE; | |
| 65 | |
| 66 // Sets the channel manager associated with this channel. This should be set | |
| 67 // at most once and only called before |WillShutdownSoon()| (and | |
| 68 // |Shutdown()|). (This is called by the channel manager when adding a | |
| 69 // channel; this should not be called before the channel is managed by the | |
| 70 // channel manager.) | |
| 71 void SetChannelManager(ChannelManager* channel_manager); | |
| 72 | |
| 73 // This must be called on the creation thread before destruction (which can | |
| 74 // happen on any thread). | |
| 75 void Shutdown(); | |
| 76 | |
| 77 // Signals that |Shutdown()| will be called soon (this may be called from any | |
| 78 // thread, unlike |Shutdown()|). Warnings will be issued if, e.g., messages | |
| 79 // are written after this is called; other warnings may be suppressed. (This | |
| 80 // may be called multiple times, or not at all.) | |
| 81 // | |
| 82 // If set, the channel manager associated with this channel will be reset. | |
| 83 void WillShutdownSoon(); | |
| 84 | |
| 85 // Called to set (i.e., attach and run) the bootstrap (first) endpoint on the | |
| 86 // channel. Both the local and remote IDs are the bootstrap ID (given by | |
| 87 // |ChannelEndpointId::GetBootstrap()|). | |
| 88 // | |
| 89 // (Bootstrapping is symmetric: Both sides call this, which will establish the | |
| 90 // first connection across a channel.) | |
| 91 void SetBootstrapEndpoint(scoped_refptr<ChannelEndpoint> endpoint); | |
| 92 | |
| 93 // Like |SetBootstrapEndpoint()|, but with explicitly-specified local and | |
| 94 // remote IDs. | |
| 95 // | |
| 96 // (Bootstrapping is still symmetric, though the sides should obviously | |
| 97 // interchange local and remote IDs. This can be used to allow multiple | |
| 98 // "bootstrap" endpoints, though this is really most useful for testing.) | |
| 99 void SetBootstrapEndpointWithIds(scoped_refptr<ChannelEndpoint> endpoint, | |
| 100 ChannelEndpointId local_id, | |
| 101 ChannelEndpointId remote_id); | |
| 102 | |
| 103 // This forwards |message| verbatim to |raw_channel_|. | |
| 104 bool WriteMessage(scoped_ptr<MessageInTransit> message); | |
| 105 | |
| 106 // See |RawChannel::IsWriteBufferEmpty()|. | |
| 107 // TODO(vtl): Maybe we shouldn't expose this, and instead have a | |
| 108 // |FlushWriteBufferAndShutdown()| or something like that. | |
| 109 bool IsWriteBufferEmpty(); | |
| 110 | |
| 111 // Removes the given endpoint from this channel (|local_id| and |remote_id| | |
| 112 // are specified as an optimization; the latter should be an invalid | |
| 113 // |ChannelEndpointId| if the endpoint is not yet running). Note: If this is | |
| 114 // called, the |Channel| will *not* call | |
| 115 // |ChannelEndpoint::DetachFromChannel()|. | |
| 116 void DetachEndpoint(ChannelEndpoint* endpoint, | |
| 117 ChannelEndpointId local_id, | |
| 118 ChannelEndpointId remote_id); | |
| 119 | |
| 120 // Returns the size of a serialized endpoint (see |SerializeEndpoint...()| and | |
| 121 // |DeserializeEndpoint()| below). This value will remain constant for a given | |
| 122 // instance of |Channel|. | |
| 123 size_t GetSerializedEndpointSize() const; | |
| 124 | |
| 125 // Endpoint serialization methods: From the |Channel|'s point of view, there | |
| 126 // are three cases (discussed further below) and thus three methods. | |
| 127 // | |
| 128 // All three methods have a |destination| argument, which should be a buffer | |
| 129 // to which auxiliary information will be written and which should be | |
| 130 // transmitted to the peer |Channel| by some other means, but using this | |
| 131 // |Channel|. It should be a buffer of (at least) the size returned by | |
| 132 // |GetSerializedEndpointSize()| (exactly that much data will be written). | |
| 133 // | |
| 134 // All three also have a |message_queue| argument, which if non-null is the | |
| 135 // queue of messages already received by the endpoint to be serialized. | |
| 136 // | |
| 137 // Note that "serialize" really means "send" -- the |endpoint| will be sent | |
| 138 // "immediately". The contents of the |destination| buffer can then be used to | |
| 139 // claim the rematerialized endpoint from the peer |Channel|. (|destination| | |
| 140 // must be sent using this |Channel|, since otherwise it may be received | |
| 141 // before it is valid to the peer |Channel|.) | |
| 142 // | |
| 143 // Case 1: The endpoint's peer is already closed. | |
| 144 // | |
| 145 // Case 2: The endpoint's peer is local (i.e., it has a | |
| 146 // |ChannelEndpointClient| but no peer |ChannelEndpoint|). | |
| 147 // | |
| 148 // Case 3: The endpoint's peer is remote (i.e., it has a peer | |
| 149 // |ChannelEndpoint|). (This has two subcases: the peer endpoint may be on | |
| 150 // this |Channel| or another |Channel|.) | |
| 151 void SerializeEndpointWithClosedPeer(void* destination, | |
| 152 MessageInTransitQueue* message_queue); | |
| 153 // This one returns the |ChannelEndpoint| for the serialized endpoint (which | |
| 154 // can be used by, e.g., a |ProxyMessagePipeEndpoint|. | |
| 155 scoped_refptr<ChannelEndpoint> SerializeEndpointWithLocalPeer( | |
| 156 void* destination, | |
| 157 MessageInTransitQueue* message_queue, | |
| 158 ChannelEndpointClient* endpoint_client, | |
| 159 unsigned endpoint_client_port); | |
| 160 void SerializeEndpointWithRemotePeer( | |
| 161 void* destination, | |
| 162 MessageInTransitQueue* message_queue, | |
| 163 scoped_refptr<ChannelEndpoint> peer_endpoint); | |
| 164 | |
| 165 // Deserializes an endpoint that was sent from the peer |Channel| (using | |
| 166 // |SerializeEndpoint...()|. |source| should be (a copy of) the data that | |
| 167 // |SerializeEndpoint...()| wrote, and must be (at least) | |
| 168 // |GetSerializedEndpointSize()| bytes. This returns the deserialized | |
| 169 // |IncomingEndpoint| (which can be converted into a |MessagePipe|) or null on | |
| 170 // error. | |
| 171 scoped_refptr<IncomingEndpoint> DeserializeEndpoint(const void* source); | |
| 172 | |
| 173 // See |RawChannel::GetSerializedPlatformHandleSize()|. | |
| 174 size_t GetSerializedPlatformHandleSize() const; | |
| 175 | |
| 176 embedder::PlatformSupport* platform_support() const { | |
| 177 return platform_support_; | |
| 178 } | |
| 179 | |
| 180 private: | |
| 181 friend class base::RefCountedThreadSafe<Channel>; | |
| 182 ~Channel() override; | |
| 183 | |
| 184 // |RawChannel::Delegate| implementation (only called on the creation thread): | |
| 185 void OnReadMessage( | |
| 186 const MessageInTransit::View& message_view, | |
| 187 embedder::ScopedPlatformHandleVectorPtr platform_handles) override; | |
| 188 void OnError(Error error) override; | |
| 189 | |
| 190 // Helpers for |OnReadMessage| (only called on the creation thread): | |
| 191 void OnReadMessageForEndpoint( | |
| 192 const MessageInTransit::View& message_view, | |
| 193 embedder::ScopedPlatformHandleVectorPtr platform_handles); | |
| 194 void OnReadMessageForChannel( | |
| 195 const MessageInTransit::View& message_view, | |
| 196 embedder::ScopedPlatformHandleVectorPtr platform_handles); | |
| 197 | |
| 198 // Handles "attach and run endpoint" messages. | |
| 199 bool OnAttachAndRunEndpoint(ChannelEndpointId local_id, | |
| 200 ChannelEndpointId remote_id); | |
| 201 // Handles "remove endpoint" messages. | |
| 202 bool OnRemoveEndpoint(ChannelEndpointId local_id, | |
| 203 ChannelEndpointId remote_id); | |
| 204 // Handles "remove endpoint ack" messages. | |
| 205 bool OnRemoveEndpointAck(ChannelEndpointId local_id); | |
| 206 | |
| 207 // Handles errors (e.g., invalid messages) from the remote side. Callable from | |
| 208 // any thread. | |
| 209 void HandleRemoteError(const char* error_message); | |
| 210 // Handles internal errors/failures from the local side. Callable from any | |
| 211 // thread. | |
| 212 void HandleLocalError(const char* error_message); | |
| 213 | |
| 214 // Helper for |SerializeEndpoint...()|: Attaches the given (non-bootstrap) | |
| 215 // endpoint to this channel and runs it. This assigns the endpoint both local | |
| 216 // and remote IDs. This will also send a | |
| 217 // |Subtype::CHANNEL_ATTACH_AND_RUN_ENDPOINT| message to the remote side to | |
| 218 // tell it to create an endpoint as well. This returns the *remote* ID (one | |
| 219 // for which |is_remote()| returns true). If |WillShutdownSoon()| has been | |
| 220 // called, |endpoint| will not be attached to this channel, and this will | |
| 221 // return an invalid ID. | |
| 222 // | |
| 223 // TODO(vtl): Maybe limit the number of attached message pipes. | |
| 224 ChannelEndpointId AttachAndRunEndpoint( | |
| 225 scoped_refptr<ChannelEndpoint> endpoint); | |
| 226 | |
| 227 // Helper to send channel control messages. Returns true on success. Callable | |
| 228 // from any thread. | |
| 229 bool SendControlMessage(MessageInTransit::Subtype subtype, | |
| 230 ChannelEndpointId source_id, | |
| 231 ChannelEndpointId destination_id) | |
| 232 MOJO_LOCKS_EXCLUDED(mutex_); | |
| 233 | |
| 234 base::ThreadChecker creation_thread_checker_; | |
| 235 | |
| 236 embedder::PlatformSupport* const platform_support_; | |
| 237 | |
| 238 // Note: |ChannelEndpointClient|s (in particular, |MessagePipe|s) MUST NOT be | |
| 239 // used under |mutex_|. E.g., |mutex_| can only be acquired after | |
| 240 // |MessagePipe::lock_|, never before. Thus to call into a | |
| 241 // |ChannelEndpointClient|, a reference should be acquired from | |
| 242 // |local_id_to_endpoint_map_| under |mutex_| and then the lock released. | |
| 243 // TODO(vtl): Annotate the above rule using |MOJO_ACQUIRED_{BEFORE,AFTER}()|, | |
| 244 // once clang actually checks such annotations. | |
| 245 // https://github.com/domokit/mojo/issues/313 | |
| 246 mutable Mutex mutex_; | |
| 247 | |
| 248 scoped_ptr<RawChannel> raw_channel_ MOJO_GUARDED_BY(mutex_); | |
| 249 bool is_running_ MOJO_GUARDED_BY(mutex_); | |
| 250 // Set when |WillShutdownSoon()| is called. | |
| 251 bool is_shutting_down_ MOJO_GUARDED_BY(mutex_); | |
| 252 | |
| 253 // Has a reference to us. | |
| 254 ChannelManager* channel_manager_ MOJO_GUARDED_BY(mutex_); | |
| 255 | |
| 256 using IdToEndpointMap = | |
| 257 base::hash_map<ChannelEndpointId, scoped_refptr<ChannelEndpoint>>; | |
| 258 // Map from local IDs to endpoints. If the endpoint is null, this means that | |
| 259 // we're just waiting for the remove ack before removing the entry. | |
| 260 IdToEndpointMap local_id_to_endpoint_map_ MOJO_GUARDED_BY(mutex_); | |
| 261 // Note: The IDs generated by this should be checked for existence before use. | |
| 262 LocalChannelEndpointIdGenerator local_id_generator_ MOJO_GUARDED_BY(mutex_); | |
| 263 | |
| 264 using IdToIncomingEndpointMap = | |
| 265 base::hash_map<ChannelEndpointId, scoped_refptr<IncomingEndpoint>>; | |
| 266 // Map from local IDs to incoming endpoints (i.e., those received inside other | |
| 267 // messages, but not yet claimed via |DeserializeEndpoint()|). | |
| 268 IdToIncomingEndpointMap incoming_endpoints_ MOJO_GUARDED_BY(mutex_); | |
| 269 // TODO(vtl): We need to keep track of remote IDs (so that we don't collide | |
| 270 // if/when we wrap). | |
| 271 RemoteChannelEndpointIdGenerator remote_id_generator_ MOJO_GUARDED_BY(mutex_); | |
| 272 | |
| 273 using EndpointList = std::vector<scoped_refptr<ChannelEndpoint>>; | |
| 274 // List of endpoints that were created while this |Channel| was being shut | |
| 275 // down. These are created, but have not been attached to this |Channel| and | |
| 276 // need to be shut down after all attached |ChannelEndpoint|s have been | |
| 277 // detached. | |
| 278 EndpointList aborted_endpoints_ MOJO_GUARDED_BY(mutex_); | |
| 279 | |
| 280 MOJO_DISALLOW_COPY_AND_ASSIGN(Channel); | |
| 281 }; | |
| 282 | |
| 283 } // namespace system | |
| 284 } // namespace mojo | |
| 285 | |
| 286 #endif // THIRD_PARTY_MOJO_SRC_MOJO_EDK_SYSTEM_CHANNEL_H_ | |
| OLD | NEW |