blob: 21fc76d40bc078cc216ce2525fe0b586d1903185 [file] [log] [blame]
[email protected]83fc55e42013-10-15 10:57:491// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]65412272010-12-21 20:03:242// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]83fc55e42013-10-15 10:57:495#include "content/browser/message_port_service.h"
[email protected]65412272010-12-21 20:03:246
avib7348942015-12-25 20:57:107#include <stddef.h>
8
[email protected]83fc55e42013-10-15 10:57:499#include "content/common/message_port_messages.h"
meke6b83032014-12-19 23:35:3410#include "content/public/browser/browser_thread.h"
sgurund2a430602015-01-23 20:54:0511#include "content/public/browser/message_port_delegate.h"
[email protected]65412272010-12-21 20:03:2412
[email protected]e6047e4a2012-10-25 01:34:4913namespace content {
14
[email protected]65412272010-12-21 20:03:2415struct MessagePortService::MessagePort {
meke6b83032014-12-19 23:35:3416 // |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;
[email protected]65412272010-12-21 20:03:2420 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.
[email protected]764a01b12013-09-19 15:18:5326 // 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
[email protected]83fc55e42013-10-15 10:57:4932 // MessagePortHostMsg_QueueMessages.
mekddb153282014-11-21 00:31:2033 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
meke6b83032014-12-19 23:35:3439 // MessagePortDelegate available for that new process. Once the
mekddb153282014-11-21 00:31:2040 // 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;
[email protected]65412272010-12-21 20:03:2451 QueuedMessages queued_messages;
52};
53
54MessagePortService* MessagePortService::GetInstance() {
olli.raula36aa8be2015-09-10 11:14:2255 return base::Singleton<MessagePortService>::get();
[email protected]65412272010-12-21 20:03:2456}
57
58MessagePortService::MessagePortService()
59 : next_message_port_id_(0) {
60}
61
62MessagePortService::~MessagePortService() {
63}
64
meke6b83032014-12-19 23:35:3465void MessagePortService::UpdateMessagePort(int message_port_id,
66 MessagePortDelegate* delegate,
67 int routing_id) {
kaliamoorthi721247d2015-02-20 14:09:0768 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]65412272010-12-21 20:03:2469 if (!message_ports_.count(message_port_id)) {
70 NOTREACHED();
71 return;
72 }
73
74 MessagePort& port = message_ports_[message_port_id];
meke6b83032014-12-19 23:35:3475 port.delegate = delegate;
[email protected]65412272010-12-21 20:03:2476 port.route_id = routing_id;
77}
78
mek9e86f80a2015-05-20 17:51:4179void 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
meke6b83032014-12-19 23:35:3495void MessagePortService::OnMessagePortDelegateClosing(
96 MessagePortDelegate* delegate) {
kaliamoorthi721247d2015-02-20 14:09:0797 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]65412272010-12-21 20:03:2498 // 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++;
meke6b83032014-12-19 23:35:34102 if (cur_item->second.delegate == delegate) {
[email protected]65412272010-12-21 20:03:24103 Erase(cur_item->first);
104 }
105 }
106}
107
108void MessagePortService::Create(int route_id,
meke6b83032014-12-19 23:35:34109 MessagePortDelegate* delegate,
[email protected]65412272010-12-21 20:03:24110 int* message_port_id) {
kaliamoorthi721247d2015-02-20 14:09:07111 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]65412272010-12-21 20:03:24112 *message_port_id = ++next_message_port_id_;
113
114 MessagePort port;
meke6b83032014-12-19 23:35:34115 port.delegate = delegate;
[email protected]65412272010-12-21 20:03:24116 port.route_id = route_id;
117 port.message_port_id = *message_port_id;
118 port.entangled_message_port_id = MSG_ROUTING_NONE;
mekddb153282014-11-21 00:31:20119 port.queue_for_inflight_messages = false;
120 port.hold_messages_for_destination = false;
121 port.should_be_destroyed = false;
[email protected]65412272010-12-21 20:03:24122 message_ports_[*message_port_id] = port;
123}
124
125void MessagePortService::Destroy(int message_port_id) {
kaliamoorthi721247d2015-02-20 14:09:07126 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]65412272010-12-21 20:03:24127 if (!message_ports_.count(message_port_id)) {
128 NOTREACHED();
129 return;
130 }
131
132 DCHECK(message_ports_[message_port_id].queued_messages.empty());
mekddb153282014-11-21 00:31:20133
[email protected]65412272010-12-21 20:03:24134 Erase(message_port_id);
135}
136
137void MessagePortService::Entangle(int local_message_port_id,
138 int remote_message_port_id) {
kaliamoorthi721247d2015-02-20 14:09:07139 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]65412272010-12-21 20:03:24140 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
152void MessagePortService::PostMessage(
153 int sender_message_port_id,
mek09ac29cee2015-02-27 19:12:39154 const MessagePortMessage& message,
mek5b679c92015-02-28 02:38:06155 const std::vector<TransferredMessagePort>& sent_message_ports) {
kaliamoorthi721247d2015-02-20 14:09:07156 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]65412272010-12-21 20:03:24157 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
mek5b679c92015-02-28 02:38:06172 PostMessageTo(entangled_message_port_id, message, sent_message_ports);
[email protected]65412272010-12-21 20:03:24173}
174
175void MessagePortService::PostMessageTo(
176 int message_port_id,
mek09ac29cee2015-02-27 19:12:39177 const MessagePortMessage& message,
mek5b679c92015-02-28 02:38:06178 const std::vector<TransferredMessagePort>& sent_message_ports) {
[email protected]65412272010-12-21 20:03:24179 if (!message_ports_.count(message_port_id)) {
180 NOTREACHED();
181 return;
182 }
mek5b679c92015-02-28 02:38:06183 for (size_t i = 0; i < sent_message_ports.size(); ++i) {
184 if (!message_ports_.count(sent_message_ports[i].id)) {
[email protected]65412272010-12-21 20:03:24185 NOTREACHED();
186 return;
187 }
188 }
189
190 MessagePort& entangled_port = message_ports_[message_port_id];
mekddb153282014-11-21 00:31:20191 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) {
mek5b679c92015-02-28 02:38:06196 for (const auto& port : sent_message_ports)
197 HoldMessages(port.id);
mekddb153282014-11-21 00:31:20198 }
[email protected]65412272010-12-21 20:03:24199 entangled_port.queued_messages.push_back(
mek5b679c92015-02-28 02:38:06200 std::make_pair(message, sent_message_ports));
mek9e86f80a2015-05-20 17:51:41201
202 if (entangled_port.delegate)
203 entangled_port.delegate->MessageWasHeld(entangled_port.route_id);
204
[email protected]65412272010-12-21 20:03:24205 return;
206 }
207
meke6b83032014-12-19 23:35:34208 if (!entangled_port.delegate) {
[email protected]65412272010-12-21 20:03:24209 NOTREACHED();
210 return;
211 }
212
[email protected]65412272010-12-21 20:03:24213 // Now send the message to the entangled port.
meke6b83032014-12-19 23:35:34214 entangled_port.delegate->SendMessage(entangled_port.route_id, message,
mek5b679c92015-02-28 02:38:06215 sent_message_ports);
[email protected]65412272010-12-21 20:03:24216}
217
218void MessagePortService::QueueMessages(int message_port_id) {
kaliamoorthi721247d2015-02-20 14:09:07219 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]65412272010-12-21 20:03:24220 if (!message_ports_.count(message_port_id)) {
221 NOTREACHED();
222 return;
223 }
224
225 MessagePort& port = message_ports_[message_port_id];
meke6b83032014-12-19 23:35:34226 if (port.delegate) {
227 port.delegate->SendMessagesAreQueued(port.route_id);
mekddb153282014-11-21 00:31:20228 port.queue_for_inflight_messages = true;
meke6b83032014-12-19 23:35:34229 port.delegate = NULL;
[email protected]65412272010-12-21 20:03:24230 }
231}
232
233void MessagePortService::SendQueuedMessages(
234 int message_port_id,
235 const QueuedMessages& queued_messages) {
kaliamoorthi721247d2015-02-20 14:09:07236 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]65412272010-12-21 20:03:24237 if (!message_ports_.count(message_port_id)) {
238 NOTREACHED();
239 return;
240 }
241
242 // Send the queued messages to the port again. This time they'll reach the
243 // new location.
244 MessagePort& port = message_ports_[message_port_id];
mekddb153282014-11-21 00:31:20245 port.queue_for_inflight_messages = false;
246
247 // If the port is currently holding messages waiting for the target renderer,
248 // all ports in messages being sent to the port should also be put on hold.
249 if (port.hold_messages_for_destination) {
250 for (const auto& message : queued_messages)
mek5b679c92015-02-28 02:38:06251 for (const TransferredMessagePort& sent_port : message.second)
252 HoldMessages(sent_port.id);
mekddb153282014-11-21 00:31:20253 }
254
[email protected]65412272010-12-21 20:03:24255 port.queued_messages.insert(port.queued_messages.begin(),
256 queued_messages.begin(),
257 queued_messages.end());
mekddb153282014-11-21 00:31:20258
259 if (port.should_be_destroyed)
260 ClosePort(message_port_id);
261 else
262 SendQueuedMessagesIfPossible(message_port_id);
[email protected]65412272010-12-21 20:03:24263}
264
265void MessagePortService::SendQueuedMessagesIfPossible(int message_port_id) {
kaliamoorthi721247d2015-02-20 14:09:07266 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]65412272010-12-21 20:03:24267 if (!message_ports_.count(message_port_id)) {
268 NOTREACHED();
269 return;
270 }
271
272 MessagePort& port = message_ports_[message_port_id];
meke6b83032014-12-19 23:35:34273 if (port.queue_messages() || !port.delegate)
[email protected]65412272010-12-21 20:03:24274 return;
275
276 for (QueuedMessages::iterator iter = port.queued_messages.begin();
277 iter != port.queued_messages.end(); ++iter) {
278 PostMessageTo(message_port_id, iter->first, iter->second);
279 }
280 port.queued_messages.clear();
281}
282
mekddb153282014-11-21 00:31:20283void MessagePortService::HoldMessages(int message_port_id) {
kaliamoorthi721247d2015-02-20 14:09:07284 DCHECK_CURRENTLY_ON(BrowserThread::IO);
mekddb153282014-11-21 00:31:20285 if (!message_ports_.count(message_port_id)) {
286 NOTREACHED();
287 return;
288 }
289
290 // Any ports in messages currently in the queue should also be put on hold.
291 for (const auto& message : message_ports_[message_port_id].queued_messages)
mek5b679c92015-02-28 02:38:06292 for (const TransferredMessagePort& sent_port : message.second)
293 HoldMessages(sent_port.id);
mekddb153282014-11-21 00:31:20294
295 message_ports_[message_port_id].hold_messages_for_destination = true;
296}
297
298void MessagePortService::ClosePort(int message_port_id) {
kaliamoorthi721247d2015-02-20 14:09:07299 DCHECK_CURRENTLY_ON(BrowserThread::IO);
mekddb153282014-11-21 00:31:20300 if (!message_ports_.count(message_port_id)) {
301 NOTREACHED();
302 return;
303 }
304
305 if (message_ports_[message_port_id].queue_for_inflight_messages) {
306 message_ports_[message_port_id].should_be_destroyed = true;
307 return;
308 }
309
310 // First close any message ports in the queue for this message port.
311 for (const auto& message : message_ports_[message_port_id].queued_messages)
mek5b679c92015-02-28 02:38:06312 for (const TransferredMessagePort& sent_port : message.second)
313 ClosePort(sent_port.id);
mekddb153282014-11-21 00:31:20314
315 Erase(message_port_id);
316}
317
318void MessagePortService::ReleaseMessages(int message_port_id) {
kaliamoorthi721247d2015-02-20 14:09:07319 DCHECK_CURRENTLY_ON(BrowserThread::IO);
mekddb153282014-11-21 00:31:20320 if (!message_ports_.count(message_port_id)) {
321 NOTREACHED();
322 return;
323 }
324
325 message_ports_[message_port_id].hold_messages_for_destination = false;
326 SendQueuedMessagesIfPossible(message_port_id);
327}
328
[email protected]65412272010-12-21 20:03:24329void MessagePortService::Erase(int message_port_id) {
330 MessagePorts::iterator erase_item = message_ports_.find(message_port_id);
331 DCHECK(erase_item != message_ports_.end());
332
333 int entangled_id = erase_item->second.entangled_message_port_id;
334 if (entangled_id != MSG_ROUTING_NONE) {
335 // Do the disentanglement (and be paranoid about the other side existing
336 // just in case something unusual happened during entanglement).
337 if (message_ports_.count(entangled_id)) {
338 message_ports_[entangled_id].entangled_message_port_id = MSG_ROUTING_NONE;
339 }
340 }
341 message_ports_.erase(erase_item);
342}
[email protected]e6047e4a2012-10-25 01:34:49343
344} // namespace content