OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/message_port_service.h" | 5 #include "content/browser/message_port_service.h" |
6 | 6 |
7 #include "content/browser/message_port_message_filter.h" | 7 #include "content/browser/message_port_message_filter.h" |
8 #include "content/common/message_port_messages.h" | 8 #include "content/common/message_port_messages.h" |
9 | 9 |
10 namespace content { | 10 namespace content { |
11 | 11 |
12 struct MessagePortService::MessagePort { | 12 struct MessagePortService::MessagePort { |
13 // |filter| and |route_id| are what we need to send messages to the port. | 13 // |filter| and |route_id| are what we need to send messages to the port. |
14 // |filter| is just a weak pointer since we get notified when its process has | 14 // |filter| is just a weak pointer since we get notified when its process has |
15 // gone away and remove it. | 15 // gone away and remove it. |
16 MessagePortMessageFilter* filter; | 16 MessagePortMessageFilter* filter; |
17 int route_id; | 17 int route_id; |
18 // A globally unique id for this message port. | 18 // A globally unique id for this message port. |
19 int message_port_id; | 19 int message_port_id; |
20 // The globally unique id of the entangled message port. | 20 // The globally unique id of the entangled message port. |
21 int entangled_message_port_id; | 21 int entangled_message_port_id; |
22 // If true, all messages to this message port are queued and not delivered. | 22 // If true, all messages to this message port are queued and not delivered. |
23 // This is needed so that when a message port is sent between processes all | 23 // This is needed so that when a message port is sent between processes all |
24 // pending message get transferred. There are two possibilities for pending | 24 // pending message get transferred. There are two possibilities for pending |
25 // messages: either they are already received by the child process, or they're | 25 // messages: either they are already received by the child process, or they're |
26 // in-flight. This flag ensures that the latter type get flushed through the | 26 // in-flight. This flag ensures that the latter type get flushed through the |
27 // system. | 27 // system. |
28 // This flag should only be set to true in response to | 28 // This flag should only be set to true in response to |
29 // MessagePortHostMsg_QueueMessages. | 29 // MessagePortHostMsg_QueueMessages. |
30 bool queue_messages; | 30 bool queue_for_inflight_messages; |
31 // If true, all messages to this message port are queued and not delivered. | |
32 // This is needed so that when a message port is sent to a new process all | |
33 // messages are held in the browser process until the destination process is | |
34 // ready to receive messages. This flag is set true when a message port is | |
35 // transferred to a different process but there isn't immediately a | |
36 // MessagePortMessageFilter available for that new process. Once the | |
37 // destination process is ready to receive messages it sends | |
38 // MessagePortHostMsg_ReleaseMessages to set this flag to false. | |
39 bool hold_messages_for_destination; | |
40 // Returns true if messages should be queued for either reason. | |
41 bool queue_messages() const { | |
42 return queue_for_inflight_messages || hold_messages_for_destination; | |
43 } | |
44 // If true, the message port should be destroyed but was currently still | |
45 // waiting for a SendQueuedMessages message from a renderer. As soon as that | |
46 // message is received the port will actually be destroyed. | |
47 bool should_be_destroyed; | |
31 QueuedMessages queued_messages; | 48 QueuedMessages queued_messages; |
32 }; | 49 }; |
33 | 50 |
34 MessagePortService* MessagePortService::GetInstance() { | 51 MessagePortService* MessagePortService::GetInstance() { |
35 return Singleton<MessagePortService>::get(); | 52 return Singleton<MessagePortService>::get(); |
36 } | 53 } |
37 | 54 |
38 MessagePortService::MessagePortService() | 55 MessagePortService::MessagePortService() |
39 : next_message_port_id_(0) { | 56 : next_message_port_id_(0) { |
40 } | 57 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
72 MessagePortMessageFilter* filter, | 89 MessagePortMessageFilter* filter, |
73 int* message_port_id) { | 90 int* message_port_id) { |
74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
75 *message_port_id = ++next_message_port_id_; | 92 *message_port_id = ++next_message_port_id_; |
76 | 93 |
77 MessagePort port; | 94 MessagePort port; |
78 port.filter = filter; | 95 port.filter = filter; |
79 port.route_id = route_id; | 96 port.route_id = route_id; |
80 port.message_port_id = *message_port_id; | 97 port.message_port_id = *message_port_id; |
81 port.entangled_message_port_id = MSG_ROUTING_NONE; | 98 port.entangled_message_port_id = MSG_ROUTING_NONE; |
82 port.queue_messages = false; | 99 port.queue_for_inflight_messages = false; |
100 port.hold_messages_for_destination = false; | |
101 port.should_be_destroyed = false; | |
83 message_ports_[*message_port_id] = port; | 102 message_ports_[*message_port_id] = port; |
84 } | 103 } |
85 | 104 |
86 void MessagePortService::Destroy(int message_port_id) { | 105 void MessagePortService::Destroy(int message_port_id) { |
87 if (!message_ports_.count(message_port_id)) { | 106 if (!message_ports_.count(message_port_id)) { |
88 NOTREACHED(); | 107 NOTREACHED(); |
89 return; | 108 return; |
90 } | 109 } |
91 | 110 |
92 DCHECK(message_ports_[message_port_id].queued_messages.empty()); | 111 DCHECK(message_ports_[message_port_id].queued_messages.empty()); |
112 | |
93 Erase(message_port_id); | 113 Erase(message_port_id); |
94 } | 114 } |
95 | 115 |
96 void MessagePortService::Entangle(int local_message_port_id, | 116 void MessagePortService::Entangle(int local_message_port_id, |
97 int remote_message_port_id) { | 117 int remote_message_port_id) { |
98 if (!message_ports_.count(local_message_port_id) || | 118 if (!message_ports_.count(local_message_port_id) || |
99 !message_ports_.count(remote_message_port_id)) { | 119 !message_ports_.count(remote_message_port_id)) { |
100 NOTREACHED(); | 120 NOTREACHED(); |
101 return; | 121 return; |
102 } | 122 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
143 return; | 163 return; |
144 } | 164 } |
145 } | 165 } |
146 | 166 |
147 MessagePort& entangled_port = message_ports_[message_port_id]; | 167 MessagePort& entangled_port = message_ports_[message_port_id]; |
148 | 168 |
149 std::vector<MessagePort*> sent_ports(sent_message_port_ids.size()); | 169 std::vector<MessagePort*> sent_ports(sent_message_port_ids.size()); |
150 for (size_t i = 0; i < sent_message_port_ids.size(); ++i) | 170 for (size_t i = 0; i < sent_message_port_ids.size(); ++i) |
151 sent_ports[i] = &message_ports_[sent_message_port_ids[i]]; | 171 sent_ports[i] = &message_ports_[sent_message_port_ids[i]]; |
152 | 172 |
153 if (entangled_port.queue_messages) { | 173 if (entangled_port.queue_messages()) { |
174 // If the target port is currently holding messages because the destination | |
175 // renderer isn't available yet, all message ports being sent should also be | |
176 // put in this state. | |
177 if (entangled_port.hold_messages_for_destination) { | |
178 for (int sent_message_port_id : sent_message_port_ids) | |
179 HoldMessages(sent_message_port_id); | |
180 } | |
154 entangled_port.queued_messages.push_back( | 181 entangled_port.queued_messages.push_back( |
155 std::make_pair(message, sent_message_port_ids)); | 182 std::make_pair(message, sent_message_port_ids)); |
156 return; | 183 return; |
157 } | 184 } |
158 | 185 |
159 if (!entangled_port.filter) { | 186 if (!entangled_port.filter) { |
160 NOTREACHED(); | 187 NOTREACHED(); |
161 return; | 188 return; |
162 } | 189 } |
163 | 190 |
(...skipping 17 matching lines...) Expand all Loading... | |
181 | 208 |
182 void MessagePortService::QueueMessages(int message_port_id) { | 209 void MessagePortService::QueueMessages(int message_port_id) { |
183 if (!message_ports_.count(message_port_id)) { | 210 if (!message_ports_.count(message_port_id)) { |
184 NOTREACHED(); | 211 NOTREACHED(); |
185 return; | 212 return; |
186 } | 213 } |
187 | 214 |
188 MessagePort& port = message_ports_[message_port_id]; | 215 MessagePort& port = message_ports_[message_port_id]; |
189 if (port.filter) { | 216 if (port.filter) { |
190 port.filter->Send(new MessagePortMsg_MessagesQueued(port.route_id)); | 217 port.filter->Send(new MessagePortMsg_MessagesQueued(port.route_id)); |
191 port.queue_messages = true; | 218 port.queue_for_inflight_messages = true; |
192 port.filter = NULL; | 219 port.filter = NULL; |
193 } | 220 } |
194 } | 221 } |
195 | 222 |
196 void MessagePortService::SendQueuedMessages( | 223 void MessagePortService::SendQueuedMessages( |
197 int message_port_id, | 224 int message_port_id, |
198 const QueuedMessages& queued_messages) { | 225 const QueuedMessages& queued_messages) { |
199 if (!message_ports_.count(message_port_id)) { | 226 if (!message_ports_.count(message_port_id)) { |
200 NOTREACHED(); | 227 NOTREACHED(); |
201 return; | 228 return; |
202 } | 229 } |
203 | 230 |
204 // Send the queued messages to the port again. This time they'll reach the | 231 // Send the queued messages to the port again. This time they'll reach the |
205 // new location. | 232 // new location. |
206 MessagePort& port = message_ports_[message_port_id]; | 233 MessagePort& port = message_ports_[message_port_id]; |
207 port.queue_messages = false; | 234 port.queue_for_inflight_messages = false; |
235 | |
236 // If the port is currently holding messages waiting for the target renderer, | |
237 // all ports in messages being sent to the port should also be put on hold. | |
238 if (port.hold_messages_for_destination) { | |
239 for (const auto& message : queued_messages) | |
240 for (int sent_message_port_id : message.second) | |
241 HoldMessages(sent_message_port_id); | |
242 } | |
243 | |
208 port.queued_messages.insert(port.queued_messages.begin(), | 244 port.queued_messages.insert(port.queued_messages.begin(), |
209 queued_messages.begin(), | 245 queued_messages.begin(), |
210 queued_messages.end()); | 246 queued_messages.end()); |
211 SendQueuedMessagesIfPossible(message_port_id); | 247 |
248 if (port.should_be_destroyed) | |
249 ClosePort(message_port_id); | |
250 else | |
251 SendQueuedMessagesIfPossible(message_port_id); | |
212 } | 252 } |
213 | 253 |
214 void MessagePortService::SendQueuedMessagesIfPossible(int message_port_id) { | 254 void MessagePortService::SendQueuedMessagesIfPossible(int message_port_id) { |
215 if (!message_ports_.count(message_port_id)) { | 255 if (!message_ports_.count(message_port_id)) { |
216 NOTREACHED(); | 256 NOTREACHED(); |
217 return; | 257 return; |
218 } | 258 } |
219 | 259 |
220 MessagePort& port = message_ports_[message_port_id]; | 260 MessagePort& port = message_ports_[message_port_id]; |
221 if (port.queue_messages || !port.filter) | 261 if (port.queue_messages() || !port.filter) |
222 return; | 262 return; |
223 | 263 |
224 for (QueuedMessages::iterator iter = port.queued_messages.begin(); | 264 for (QueuedMessages::iterator iter = port.queued_messages.begin(); |
225 iter != port.queued_messages.end(); ++iter) { | 265 iter != port.queued_messages.end(); ++iter) { |
226 PostMessageTo(message_port_id, iter->first, iter->second); | 266 PostMessageTo(message_port_id, iter->first, iter->second); |
227 } | 267 } |
228 port.queued_messages.clear(); | 268 port.queued_messages.clear(); |
229 } | 269 } |
230 | 270 |
271 void MessagePortService::HoldMessages(int message_port_id) { | |
272 if (!message_ports_.count(message_port_id)) { | |
273 NOTREACHED(); | |
274 return; | |
275 } | |
276 | |
277 // Any ports in messages currently in the queue should also be put on hold. | |
278 for (const auto& message : message_ports_[message_port_id].queued_messages) | |
279 for (int sent_message_port_id : message.second) | |
280 HoldMessages(sent_message_port_id); | |
281 | |
282 message_ports_[message_port_id].hold_messages_for_destination = true; | |
283 } | |
284 | |
285 void MessagePortService::ClosePort(int message_port_id) | |
286 { | |
jam
2014/11/20 22:36:47
nit: wrong line
Marijn Kruisselbrink
2014/11/20 23:15:27
Done.
| |
287 if (!message_ports_.count(message_port_id)) { | |
288 NOTREACHED(); | |
289 return; | |
290 } | |
291 | |
292 if (message_ports_[message_port_id].queue_for_inflight_messages) { | |
293 message_ports_[message_port_id].should_be_destroyed = true; | |
294 return; | |
295 } | |
296 | |
297 // First close any message ports in the queue for this message port. | |
298 for (const auto& message : message_ports_[message_port_id].queued_messages) | |
299 for (int sent_message_port_id : message.second) | |
300 ClosePort(sent_message_port_id); | |
301 | |
302 Erase(message_port_id); | |
303 } | |
304 | |
305 void MessagePortService::ReleaseMessages(int message_port_id) { | |
306 if (!message_ports_.count(message_port_id)) { | |
307 NOTREACHED(); | |
308 return; | |
309 } | |
310 | |
311 message_ports_[message_port_id].hold_messages_for_destination = false; | |
312 SendQueuedMessagesIfPossible(message_port_id); | |
313 } | |
314 | |
231 void MessagePortService::Erase(int message_port_id) { | 315 void MessagePortService::Erase(int message_port_id) { |
232 MessagePorts::iterator erase_item = message_ports_.find(message_port_id); | 316 MessagePorts::iterator erase_item = message_ports_.find(message_port_id); |
233 DCHECK(erase_item != message_ports_.end()); | 317 DCHECK(erase_item != message_ports_.end()); |
234 | 318 |
235 int entangled_id = erase_item->second.entangled_message_port_id; | 319 int entangled_id = erase_item->second.entangled_message_port_id; |
236 if (entangled_id != MSG_ROUTING_NONE) { | 320 if (entangled_id != MSG_ROUTING_NONE) { |
237 // Do the disentanglement (and be paranoid about the other side existing | 321 // Do the disentanglement (and be paranoid about the other side existing |
238 // just in case something unusual happened during entanglement). | 322 // just in case something unusual happened during entanglement). |
239 if (message_ports_.count(entangled_id)) { | 323 if (message_ports_.count(entangled_id)) { |
240 message_ports_[entangled_id].entangled_message_port_id = MSG_ROUTING_NONE; | 324 message_ports_[entangled_id].entangled_message_port_id = MSG_ROUTING_NONE; |
241 } | 325 } |
242 } | 326 } |
243 message_ports_.erase(erase_item); | 327 message_ports_.erase(erase_item); |
244 } | 328 } |
245 | 329 |
246 } // namespace content | 330 } // namespace content |
OLD | NEW |