Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: content/browser/message_port_service.cc

Issue 2422793002: HTML MessagePort as mojo::MessagePipeHandle (Closed)
Patch Set: Add missing ScopedAsyncTaskScheduler instance for the new unit tests; required by a recent change t… Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 #include "content/browser/message_port_service.h"
6
7 #include <stddef.h>
8
9 #include "content/common/message_port_messages.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/message_port_delegate.h"
12
13 namespace content {
14
15 struct MessagePortService::MessagePort {
16 // |delegate| and |route_id| are what we need to send messages to the port.
17 // |delegate| is just a raw pointer since it notifies us by calling
18 // OnMessagePortDelegateClosing before it gets destroyed.
19 MessagePortDelegate* delegate;
20 int route_id;
21 // A globally unique id for this message port.
22 int message_port_id;
23 // The globally unique id of the entangled message port.
24 int entangled_message_port_id;
25 // If true, all messages to this message port are queued and not delivered.
26 // This is needed so that when a message port is sent between processes all
27 // pending message get transferred. There are two possibilities for pending
28 // messages: either they are already received by the child process, or they're
29 // in-flight. This flag ensures that the latter type get flushed through the
30 // system.
31 // This flag should only be set to true in response to
32 // MessagePortHostMsg_QueueMessages.
33 bool queue_for_inflight_messages;
34 // If true, all messages to this message port are queued and not delivered.
35 // This is needed so that when a message port is sent to a new process all
36 // messages are held in the browser process until the destination process is
37 // ready to receive messages. This flag is set true when a message port is
38 // transferred to a different process but there isn't immediately a
39 // MessagePortDelegate available for that new process. Once the
40 // destination process is ready to receive messages it sends
41 // MessagePortHostMsg_ReleaseMessages to set this flag to false.
42 bool hold_messages_for_destination;
43 // Returns true if messages should be queued for either reason.
44 bool queue_messages() const {
45 return queue_for_inflight_messages || hold_messages_for_destination;
46 }
47 // If true, the message port should be destroyed but was currently still
48 // waiting for a SendQueuedMessages message from a renderer. As soon as that
49 // message is received the port will actually be destroyed.
50 bool should_be_destroyed;
51 QueuedMessages queued_messages;
52 };
53
54 MessagePortService* MessagePortService::GetInstance() {
55 return base::Singleton<MessagePortService>::get();
56 }
57
58 MessagePortService::MessagePortService()
59 : next_message_port_id_(0) {
60 }
61
62 MessagePortService::~MessagePortService() {
63 }
64
65 void MessagePortService::UpdateMessagePort(int message_port_id,
66 MessagePortDelegate* delegate,
67 int routing_id) {
68 DCHECK_CURRENTLY_ON(BrowserThread::IO);
69 if (!message_ports_.count(message_port_id)) {
70 NOTREACHED();
71 return;
72 }
73
74 MessagePort& port = message_ports_[message_port_id];
75 port.delegate = delegate;
76 port.route_id = routing_id;
77 }
78
79 void MessagePortService::GetMessagePortInfo(int message_port_id,
80 MessagePortDelegate** delegate,
81 int* routing_id) {
82 DCHECK_CURRENTLY_ON(BrowserThread::IO);
83 if (!message_ports_.count(message_port_id)) {
84 NOTREACHED();
85 return;
86 }
87
88 const MessagePort& port = message_ports_[message_port_id];
89 if (delegate)
90 *delegate = port.delegate;
91 if (routing_id)
92 *routing_id = port.route_id;
93 }
94
95 void MessagePortService::OnMessagePortDelegateClosing(
96 MessagePortDelegate* delegate) {
97 DCHECK_CURRENTLY_ON(BrowserThread::IO);
98 // Check if the (possibly) crashed process had any message ports.
99 for (MessagePorts::iterator iter = message_ports_.begin();
100 iter != message_ports_.end();) {
101 MessagePorts::iterator cur_item = iter++;
102 if (cur_item->second.delegate == delegate) {
103 Erase(cur_item->first);
104 }
105 }
106 }
107
108 void MessagePortService::Create(int route_id,
109 MessagePortDelegate* delegate,
110 int* message_port_id) {
111 DCHECK_CURRENTLY_ON(BrowserThread::IO);
112 *message_port_id = ++next_message_port_id_;
113
114 MessagePort port;
115 port.delegate = delegate;
116 port.route_id = route_id;
117 port.message_port_id = *message_port_id;
118 port.entangled_message_port_id = MSG_ROUTING_NONE;
119 port.queue_for_inflight_messages = false;
120 port.hold_messages_for_destination = false;
121 port.should_be_destroyed = false;
122 message_ports_[*message_port_id] = port;
123 }
124
125 void MessagePortService::Destroy(int message_port_id) {
126 DCHECK_CURRENTLY_ON(BrowserThread::IO);
127 if (!message_ports_.count(message_port_id)) {
128 NOTREACHED();
129 return;
130 }
131
132 DCHECK(message_ports_[message_port_id].queued_messages.empty());
133
134 Erase(message_port_id);
135 }
136
137 void MessagePortService::Entangle(int local_message_port_id,
138 int remote_message_port_id) {
139 DCHECK_CURRENTLY_ON(BrowserThread::IO);
140 if (!message_ports_.count(local_message_port_id) ||
141 !message_ports_.count(remote_message_port_id)) {
142 NOTREACHED();
143 return;
144 }
145
146 DCHECK(message_ports_[remote_message_port_id].entangled_message_port_id ==
147 MSG_ROUTING_NONE);
148 message_ports_[remote_message_port_id].entangled_message_port_id =
149 local_message_port_id;
150 }
151
152 void MessagePortService::PostMessage(
153 int sender_message_port_id,
154 const base::string16& message,
155 const std::vector<int>& sent_message_ports) {
156 DCHECK_CURRENTLY_ON(BrowserThread::IO);
157 if (!message_ports_.count(sender_message_port_id)) {
158 NOTREACHED();
159 return;
160 }
161
162 int entangled_message_port_id =
163 message_ports_[sender_message_port_id].entangled_message_port_id;
164 if (entangled_message_port_id == MSG_ROUTING_NONE)
165 return; // Process could have crashed.
166
167 if (!message_ports_.count(entangled_message_port_id)) {
168 NOTREACHED();
169 return;
170 }
171
172 PostMessageTo(entangled_message_port_id, message, sent_message_ports);
173 }
174
175 void MessagePortService::PostMessageTo(
176 int message_port_id,
177 const base::string16& message,
178 const std::vector<int>& sent_message_ports) {
179 if (!message_ports_.count(message_port_id)) {
180 NOTREACHED();
181 return;
182 }
183 for (size_t i = 0; i < sent_message_ports.size(); ++i) {
184 if (!message_ports_.count(sent_message_ports[i])) {
185 NOTREACHED();
186 return;
187 }
188 }
189
190 MessagePort& entangled_port = message_ports_[message_port_id];
191 if (entangled_port.queue_messages()) {
192 // If the target port is currently holding messages because the destination
193 // renderer isn't available yet, all message ports being sent should also be
194 // put in this state.
195 if (entangled_port.hold_messages_for_destination) {
196 for (const auto& port : sent_message_ports)
197 HoldMessages(port);
198 }
199 entangled_port.queued_messages.push_back(
200 std::make_pair(message, sent_message_ports));
201 return;
202 }
203
204 if (!entangled_port.delegate) {
205 NOTREACHED();
206 return;
207 }
208
209 // Now send the message to the entangled port.
210 entangled_port.delegate->SendMessage(entangled_port.route_id, message,
211 sent_message_ports);
212 }
213
214 void MessagePortService::QueueMessages(int message_port_id) {
215 DCHECK_CURRENTLY_ON(BrowserThread::IO);
216 if (!message_ports_.count(message_port_id)) {
217 NOTREACHED();
218 return;
219 }
220
221 MessagePort& port = message_ports_[message_port_id];
222 if (port.delegate) {
223 port.delegate->SendMessagesAreQueued(port.route_id);
224 port.queue_for_inflight_messages = true;
225 port.delegate = NULL;
226 }
227 }
228
229 void MessagePortService::SendQueuedMessages(
230 int message_port_id,
231 const QueuedMessages& queued_messages) {
232 DCHECK_CURRENTLY_ON(BrowserThread::IO);
233 if (!message_ports_.count(message_port_id)) {
234 NOTREACHED();
235 return;
236 }
237
238 // Send the queued messages to the port again. This time they'll reach the
239 // new location.
240 MessagePort& port = message_ports_[message_port_id];
241 port.queue_for_inflight_messages = false;
242
243 // If the port is currently holding messages waiting for the target renderer,
244 // all ports in messages being sent to the port should also be put on hold.
245 if (port.hold_messages_for_destination) {
246 for (const auto& message : queued_messages)
247 for (int sent_port : message.second)
248 HoldMessages(sent_port);
249 }
250
251 port.queued_messages.insert(port.queued_messages.begin(),
252 queued_messages.begin(),
253 queued_messages.end());
254
255 if (port.should_be_destroyed)
256 ClosePort(message_port_id);
257 else
258 SendQueuedMessagesIfPossible(message_port_id);
259 }
260
261 void MessagePortService::SendQueuedMessagesIfPossible(int message_port_id) {
262 DCHECK_CURRENTLY_ON(BrowserThread::IO);
263 if (!message_ports_.count(message_port_id)) {
264 NOTREACHED();
265 return;
266 }
267
268 MessagePort& port = message_ports_[message_port_id];
269 if (port.queue_messages() || !port.delegate)
270 return;
271
272 for (QueuedMessages::iterator iter = port.queued_messages.begin();
273 iter != port.queued_messages.end(); ++iter) {
274 PostMessageTo(message_port_id, iter->first, iter->second);
275 }
276 port.queued_messages.clear();
277 }
278
279 void MessagePortService::HoldMessages(int message_port_id) {
280 DCHECK_CURRENTLY_ON(BrowserThread::IO);
281 if (!message_ports_.count(message_port_id)) {
282 NOTREACHED();
283 return;
284 }
285
286 // Any ports in messages currently in the queue should also be put on hold.
287 for (const auto& message : message_ports_[message_port_id].queued_messages)
288 for (int sent_port : message.second)
289 HoldMessages(sent_port);
290
291 message_ports_[message_port_id].hold_messages_for_destination = true;
292 }
293
294 bool MessagePortService::AreMessagesHeld(int message_port_id) {
295 DCHECK_CURRENTLY_ON(BrowserThread::IO);
296 if (!message_ports_.count(message_port_id))
297 return false;
298 return message_ports_[message_port_id].hold_messages_for_destination;
299 }
300
301 void MessagePortService::ClosePort(int message_port_id) {
302 DCHECK_CURRENTLY_ON(BrowserThread::IO);
303 if (!message_ports_.count(message_port_id)) {
304 NOTREACHED();
305 return;
306 }
307
308 if (message_ports_[message_port_id].queue_for_inflight_messages) {
309 message_ports_[message_port_id].should_be_destroyed = true;
310 return;
311 }
312
313 // First close any message ports in the queue for this message port.
314 for (const auto& message : message_ports_[message_port_id].queued_messages)
315 for (int sent_port : message.second)
316 ClosePort(sent_port);
317
318 Erase(message_port_id);
319 }
320
321 void MessagePortService::ReleaseMessages(int message_port_id) {
322 DCHECK_CURRENTLY_ON(BrowserThread::IO);
323 if (!message_ports_.count(message_port_id)) {
324 NOTREACHED();
325 return;
326 }
327
328 message_ports_[message_port_id].hold_messages_for_destination = false;
329 SendQueuedMessagesIfPossible(message_port_id);
330 }
331
332 void MessagePortService::Erase(int message_port_id) {
333 MessagePorts::iterator erase_item = message_ports_.find(message_port_id);
334 DCHECK(erase_item != message_ports_.end());
335
336 int entangled_id = erase_item->second.entangled_message_port_id;
337 if (entangled_id != MSG_ROUTING_NONE) {
338 // Do the disentanglement (and be paranoid about the other side existing
339 // just in case something unusual happened during entanglement).
340 if (message_ports_.count(entangled_id)) {
341 message_ports_[entangled_id].entangled_message_port_id = MSG_ROUTING_NONE;
342 }
343 }
344 message_ports_.erase(erase_item);
345 }
346
347 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/message_port_service.h ('k') | content/browser/renderer_host/render_process_host_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698