Revert of Add DumpAccessibilityEvents test framework. (patchset #7 id:120001 of https...
[chromium-blink-merge.git] / content / browser / message_port_service.cc
blob08a0aad95f4b4920aa15b997acebf5e6ff0b0665
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.
5 #include "content/browser/message_port_service.h"
7 #include "content/browser/message_port_message_filter.h"
8 #include "content/common/message_port_messages.h"
10 namespace content {
12 struct MessagePortService::MessagePort {
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
15 // gone away and remove it.
16 MessagePortMessageFilter* filter;
17 int route_id;
18 // A globally unique id for this message port.
19 int message_port_id;
20 // The globally unique id of the entangled message port.
21 int entangled_message_port_id;
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
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
26 // in-flight. This flag ensures that the latter type get flushed through the
27 // system.
28 // This flag should only be set to true in response to
29 // MessagePortHostMsg_QueueMessages.
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;
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;
48 QueuedMessages queued_messages;
51 MessagePortService* MessagePortService::GetInstance() {
52 return Singleton<MessagePortService>::get();
55 MessagePortService::MessagePortService()
56 : next_message_port_id_(0) {
59 MessagePortService::~MessagePortService() {
62 void MessagePortService::UpdateMessagePort(
63 int message_port_id,
64 MessagePortMessageFilter* filter,
65 int routing_id) {
66 if (!message_ports_.count(message_port_id)) {
67 NOTREACHED();
68 return;
71 MessagePort& port = message_ports_[message_port_id];
72 port.filter = filter;
73 port.route_id = routing_id;
76 void MessagePortService::OnMessagePortMessageFilterClosing(
77 MessagePortMessageFilter* filter) {
78 // Check if the (possibly) crashed process had any message ports.
79 for (MessagePorts::iterator iter = message_ports_.begin();
80 iter != message_ports_.end();) {
81 MessagePorts::iterator cur_item = iter++;
82 if (cur_item->second.filter == filter) {
83 Erase(cur_item->first);
88 void MessagePortService::Create(int route_id,
89 MessagePortMessageFilter* filter,
90 int* message_port_id) {
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
92 *message_port_id = ++next_message_port_id_;
94 MessagePort port;
95 port.filter = filter;
96 port.route_id = route_id;
97 port.message_port_id = *message_port_id;
98 port.entangled_message_port_id = MSG_ROUTING_NONE;
99 port.queue_for_inflight_messages = false;
100 port.hold_messages_for_destination = false;
101 port.should_be_destroyed = false;
102 message_ports_[*message_port_id] = port;
105 void MessagePortService::Destroy(int message_port_id) {
106 if (!message_ports_.count(message_port_id)) {
107 NOTREACHED();
108 return;
111 DCHECK(message_ports_[message_port_id].queued_messages.empty());
113 Erase(message_port_id);
116 void MessagePortService::Entangle(int local_message_port_id,
117 int remote_message_port_id) {
118 if (!message_ports_.count(local_message_port_id) ||
119 !message_ports_.count(remote_message_port_id)) {
120 NOTREACHED();
121 return;
124 DCHECK(message_ports_[remote_message_port_id].entangled_message_port_id ==
125 MSG_ROUTING_NONE);
126 message_ports_[remote_message_port_id].entangled_message_port_id =
127 local_message_port_id;
130 void MessagePortService::PostMessage(
131 int sender_message_port_id,
132 const base::string16& message,
133 const std::vector<int>& sent_message_port_ids) {
134 if (!message_ports_.count(sender_message_port_id)) {
135 NOTREACHED();
136 return;
139 int entangled_message_port_id =
140 message_ports_[sender_message_port_id].entangled_message_port_id;
141 if (entangled_message_port_id == MSG_ROUTING_NONE)
142 return; // Process could have crashed.
144 if (!message_ports_.count(entangled_message_port_id)) {
145 NOTREACHED();
146 return;
149 PostMessageTo(entangled_message_port_id, message, sent_message_port_ids);
152 void MessagePortService::PostMessageTo(
153 int message_port_id,
154 const base::string16& message,
155 const std::vector<int>& sent_message_port_ids) {
156 if (!message_ports_.count(message_port_id)) {
157 NOTREACHED();
158 return;
160 for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
161 if (!message_ports_.count(sent_message_port_ids[i])) {
162 NOTREACHED();
163 return;
167 MessagePort& entangled_port = message_ports_[message_port_id];
169 std::vector<MessagePort*> sent_ports(sent_message_port_ids.size());
170 for (size_t i = 0; i < sent_message_port_ids.size(); ++i)
171 sent_ports[i] = &message_ports_[sent_message_port_ids[i]];
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);
181 entangled_port.queued_messages.push_back(
182 std::make_pair(message, sent_message_port_ids));
183 return;
186 if (!entangled_port.filter) {
187 NOTREACHED();
188 return;
191 // If a message port was sent around, the new location will need a routing
192 // id. Instead of having the created port send us a sync message to get it,
193 // send along with the message.
194 std::vector<int> new_routing_ids(sent_message_port_ids.size());
195 for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
196 new_routing_ids[i] = entangled_port.filter->GetNextRoutingID();
197 sent_ports[i]->filter = entangled_port.filter;
199 // Update the entry for the sent port as it can be in a different process.
200 sent_ports[i]->route_id = new_routing_ids[i];
203 // Now send the message to the entangled port.
204 entangled_port.filter->Send(new MessagePortMsg_Message(
205 entangled_port.route_id, message, sent_message_port_ids,
206 new_routing_ids));
209 void MessagePortService::QueueMessages(int message_port_id) {
210 if (!message_ports_.count(message_port_id)) {
211 NOTREACHED();
212 return;
215 MessagePort& port = message_ports_[message_port_id];
216 if (port.filter) {
217 port.filter->Send(new MessagePortMsg_MessagesQueued(port.route_id));
218 port.queue_for_inflight_messages = true;
219 port.filter = NULL;
223 void MessagePortService::SendQueuedMessages(
224 int message_port_id,
225 const QueuedMessages& queued_messages) {
226 if (!message_ports_.count(message_port_id)) {
227 NOTREACHED();
228 return;
231 // Send the queued messages to the port again. This time they'll reach the
232 // new location.
233 MessagePort& port = message_ports_[message_port_id];
234 port.queue_for_inflight_messages = false;
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);
244 port.queued_messages.insert(port.queued_messages.begin(),
245 queued_messages.begin(),
246 queued_messages.end());
248 if (port.should_be_destroyed)
249 ClosePort(message_port_id);
250 else
251 SendQueuedMessagesIfPossible(message_port_id);
254 void MessagePortService::SendQueuedMessagesIfPossible(int message_port_id) {
255 if (!message_ports_.count(message_port_id)) {
256 NOTREACHED();
257 return;
260 MessagePort& port = message_ports_[message_port_id];
261 if (port.queue_messages() || !port.filter)
262 return;
264 for (QueuedMessages::iterator iter = port.queued_messages.begin();
265 iter != port.queued_messages.end(); ++iter) {
266 PostMessageTo(message_port_id, iter->first, iter->second);
268 port.queued_messages.clear();
271 void MessagePortService::HoldMessages(int message_port_id) {
272 if (!message_ports_.count(message_port_id)) {
273 NOTREACHED();
274 return;
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);
282 message_ports_[message_port_id].hold_messages_for_destination = true;
285 void MessagePortService::ClosePort(int message_port_id) {
286 if (!message_ports_.count(message_port_id)) {
287 NOTREACHED();
288 return;
291 if (message_ports_[message_port_id].queue_for_inflight_messages) {
292 message_ports_[message_port_id].should_be_destroyed = true;
293 return;
296 // First close any message ports in the queue for this message port.
297 for (const auto& message : message_ports_[message_port_id].queued_messages)
298 for (int sent_message_port_id : message.second)
299 ClosePort(sent_message_port_id);
301 Erase(message_port_id);
304 void MessagePortService::ReleaseMessages(int message_port_id) {
305 if (!message_ports_.count(message_port_id)) {
306 NOTREACHED();
307 return;
310 message_ports_[message_port_id].hold_messages_for_destination = false;
311 SendQueuedMessagesIfPossible(message_port_id);
314 void MessagePortService::Erase(int message_port_id) {
315 MessagePorts::iterator erase_item = message_ports_.find(message_port_id);
316 DCHECK(erase_item != message_ports_.end());
318 int entangled_id = erase_item->second.entangled_message_port_id;
319 if (entangled_id != MSG_ROUTING_NONE) {
320 // Do the disentanglement (and be paranoid about the other side existing
321 // just in case something unusual happened during entanglement).
322 if (message_ports_.count(entangled_id)) {
323 message_ports_[entangled_id].entangled_message_port_id = MSG_ROUTING_NONE;
326 message_ports_.erase(erase_item);
329 } // namespace content