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"
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
;
18 // A globally unique id for this message port.
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
28 // This flag should only be set to true in response to
29 // MessagePortHostMsg_QueueMessages.
31 QueuedMessages queued_messages
;
34 MessagePortService
* MessagePortService::GetInstance() {
35 return Singleton
<MessagePortService
>::get();
38 MessagePortService::MessagePortService()
39 : next_message_port_id_(0) {
42 MessagePortService::~MessagePortService() {
45 void MessagePortService::UpdateMessagePort(
47 MessagePortMessageFilter
* filter
,
49 if (!message_ports_
.count(message_port_id
)) {
54 MessagePort
& port
= message_ports_
[message_port_id
];
56 port
.route_id
= routing_id
;
59 void MessagePortService::OnMessagePortMessageFilterClosing(
60 MessagePortMessageFilter
* filter
) {
61 // Check if the (possibly) crashed process had any message ports.
62 for (MessagePorts::iterator iter
= message_ports_
.begin();
63 iter
!= message_ports_
.end();) {
64 MessagePorts::iterator cur_item
= iter
++;
65 if (cur_item
->second
.filter
== filter
) {
66 Erase(cur_item
->first
);
71 void MessagePortService::Create(int route_id
,
72 MessagePortMessageFilter
* filter
,
73 int* message_port_id
) {
74 *message_port_id
= ++next_message_port_id_
;
78 port
.route_id
= route_id
;
79 port
.message_port_id
= *message_port_id
;
80 port
.entangled_message_port_id
= MSG_ROUTING_NONE
;
81 port
.queue_messages
= false;
82 message_ports_
[*message_port_id
] = port
;
85 void MessagePortService::Destroy(int message_port_id
) {
86 if (!message_ports_
.count(message_port_id
)) {
91 DCHECK(message_ports_
[message_port_id
].queued_messages
.empty());
92 Erase(message_port_id
);
95 void MessagePortService::Entangle(int local_message_port_id
,
96 int remote_message_port_id
) {
97 if (!message_ports_
.count(local_message_port_id
) ||
98 !message_ports_
.count(remote_message_port_id
)) {
103 DCHECK(message_ports_
[remote_message_port_id
].entangled_message_port_id
==
105 message_ports_
[remote_message_port_id
].entangled_message_port_id
=
106 local_message_port_id
;
109 void MessagePortService::PostMessage(
110 int sender_message_port_id
,
111 const base::string16
& message
,
112 const std::vector
<int>& sent_message_port_ids
) {
113 if (!message_ports_
.count(sender_message_port_id
)) {
118 int entangled_message_port_id
=
119 message_ports_
[sender_message_port_id
].entangled_message_port_id
;
120 if (entangled_message_port_id
== MSG_ROUTING_NONE
)
121 return; // Process could have crashed.
123 if (!message_ports_
.count(entangled_message_port_id
)) {
128 PostMessageTo(entangled_message_port_id
, message
, sent_message_port_ids
);
131 void MessagePortService::PostMessageTo(
133 const base::string16
& message
,
134 const std::vector
<int>& sent_message_port_ids
) {
135 if (!message_ports_
.count(message_port_id
)) {
139 for (size_t i
= 0; i
< sent_message_port_ids
.size(); ++i
) {
140 if (!message_ports_
.count(sent_message_port_ids
[i
])) {
146 MessagePort
& entangled_port
= message_ports_
[message_port_id
];
148 std::vector
<MessagePort
*> sent_ports(sent_message_port_ids
.size());
149 for (size_t i
= 0; i
< sent_message_port_ids
.size(); ++i
)
150 sent_ports
[i
] = &message_ports_
[sent_message_port_ids
[i
]];
152 if (entangled_port
.queue_messages
) {
153 entangled_port
.queued_messages
.push_back(
154 std::make_pair(message
, sent_message_port_ids
));
158 if (!entangled_port
.filter
) {
163 // If a message port was sent around, the new location will need a routing
164 // id. Instead of having the created port send us a sync message to get it,
165 // send along with the message.
166 std::vector
<int> new_routing_ids(sent_message_port_ids
.size());
167 for (size_t i
= 0; i
< sent_message_port_ids
.size(); ++i
) {
168 new_routing_ids
[i
] = entangled_port
.filter
->GetNextRoutingID();
169 sent_ports
[i
]->filter
= entangled_port
.filter
;
171 // Update the entry for the sent port as it can be in a different process.
172 sent_ports
[i
]->route_id
= new_routing_ids
[i
];
175 // Now send the message to the entangled port.
176 entangled_port
.filter
->Send(new MessagePortMsg_Message(
177 entangled_port
.route_id
, message
, sent_message_port_ids
,
181 void MessagePortService::QueueMessages(int message_port_id
) {
182 if (!message_ports_
.count(message_port_id
)) {
187 MessagePort
& port
= message_ports_
[message_port_id
];
189 port
.filter
->Send(new MessagePortMsg_MessagesQueued(port
.route_id
));
190 port
.queue_messages
= true;
195 void MessagePortService::SendQueuedMessages(
197 const QueuedMessages
& queued_messages
) {
198 if (!message_ports_
.count(message_port_id
)) {
203 // Send the queued messages to the port again. This time they'll reach the
205 MessagePort
& port
= message_ports_
[message_port_id
];
206 port
.queue_messages
= false;
207 port
.queued_messages
.insert(port
.queued_messages
.begin(),
208 queued_messages
.begin(),
209 queued_messages
.end());
210 SendQueuedMessagesIfPossible(message_port_id
);
213 void MessagePortService::SendQueuedMessagesIfPossible(int message_port_id
) {
214 if (!message_ports_
.count(message_port_id
)) {
219 MessagePort
& port
= message_ports_
[message_port_id
];
220 if (port
.queue_messages
|| !port
.filter
)
223 for (QueuedMessages::iterator iter
= port
.queued_messages
.begin();
224 iter
!= port
.queued_messages
.end(); ++iter
) {
225 PostMessageTo(message_port_id
, iter
->first
, iter
->second
);
227 port
.queued_messages
.clear();
230 void MessagePortService::Erase(int message_port_id
) {
231 MessagePorts::iterator erase_item
= message_ports_
.find(message_port_id
);
232 DCHECK(erase_item
!= message_ports_
.end());
234 int entangled_id
= erase_item
->second
.entangled_message_port_id
;
235 if (entangled_id
!= MSG_ROUTING_NONE
) {
236 // Do the disentanglement (and be paranoid about the other side existing
237 // just in case something unusual happened during entanglement).
238 if (message_ports_
.count(entangled_id
)) {
239 message_ports_
[entangled_id
].entangled_message_port_id
= MSG_ROUTING_NONE
;
242 message_ports_
.erase(erase_item
);
245 } // namespace content