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 |