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 "content/browser/message_port_message_filter.h" 8 #include "content/common/message_port_messages.h" 9 10 namespace content { 11 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_messages; 31 QueuedMessages queued_messages; 32 }; 33 34 MessagePortService* MessagePortService::GetInstance() { 35 return Singleton<MessagePortService>::get(); 36 } 37 38 MessagePortService::MessagePortService() 39 : next_message_port_id_(0) { 40 } 41 42 MessagePortService::~MessagePortService() { 43 } 44 45 void MessagePortService::UpdateMessagePort( 46 int message_port_id, 47 MessagePortMessageFilter* filter, 48 int routing_id) { 49 if (!message_ports_.count(message_port_id)) { 50 NOTREACHED(); 51 return; 52 } 53 54 MessagePort& port = message_ports_[message_port_id]; 55 port.filter = filter; 56 port.route_id = routing_id; 57 } 58 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); 67 } 68 } 69 } 70 71 void MessagePortService::Create(int route_id, 72 MessagePortMessageFilter* filter, 73 int* message_port_id) { 74 *message_port_id = ++next_message_port_id_; 75 76 MessagePort port; 77 port.filter = filter; 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; 83 } 84 85 void MessagePortService::Destroy(int message_port_id) { 86 if (!message_ports_.count(message_port_id)) { 87 NOTREACHED(); 88 return; 89 } 90 91 DCHECK(message_ports_[message_port_id].queued_messages.empty()); 92 Erase(message_port_id); 93 } 94 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)) { 99 NOTREACHED(); 100 return; 101 } 102 103 DCHECK(message_ports_[remote_message_port_id].entangled_message_port_id == 104 MSG_ROUTING_NONE); 105 message_ports_[remote_message_port_id].entangled_message_port_id = 106 local_message_port_id; 107 } 108 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)) { 114 NOTREACHED(); 115 return; 116 } 117 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. 122 123 if (!message_ports_.count(entangled_message_port_id)) { 124 NOTREACHED(); 125 return; 126 } 127 128 PostMessageTo(entangled_message_port_id, message, sent_message_port_ids); 129 } 130 131 void MessagePortService::PostMessageTo( 132 int message_port_id, 133 const base::string16& message, 134 const std::vector<int>& sent_message_port_ids) { 135 if (!message_ports_.count(message_port_id)) { 136 NOTREACHED(); 137 return; 138 } 139 for (size_t i = 0; i < sent_message_port_ids.size(); ++i) { 140 if (!message_ports_.count(sent_message_port_ids[i])) { 141 NOTREACHED(); 142 return; 143 } 144 } 145 146 MessagePort& entangled_port = message_ports_[message_port_id]; 147 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]]; 151 152 if (entangled_port.queue_messages) { 153 entangled_port.queued_messages.push_back( 154 std::make_pair(message, sent_message_port_ids)); 155 return; 156 } 157 158 if (!entangled_port.filter) { 159 NOTREACHED(); 160 return; 161 } 162 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; 170 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]; 173 } 174 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, 178 new_routing_ids)); 179 } 180 181 void MessagePortService::QueueMessages(int message_port_id) { 182 if (!message_ports_.count(message_port_id)) { 183 NOTREACHED(); 184 return; 185 } 186 187 MessagePort& port = message_ports_[message_port_id]; 188 if (port.filter) { 189 port.filter->Send(new MessagePortMsg_MessagesQueued(port.route_id)); 190 port.queue_messages = true; 191 port.filter = NULL; 192 } 193 } 194 195 void MessagePortService::SendQueuedMessages( 196 int message_port_id, 197 const QueuedMessages& queued_messages) { 198 if (!message_ports_.count(message_port_id)) { 199 NOTREACHED(); 200 return; 201 } 202 203 // Send the queued messages to the port again. This time they'll reach the 204 // new location. 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); 211 } 212 213 void MessagePortService::SendQueuedMessagesIfPossible(int message_port_id) { 214 if (!message_ports_.count(message_port_id)) { 215 NOTREACHED(); 216 return; 217 } 218 219 MessagePort& port = message_ports_[message_port_id]; 220 if (port.queue_messages || !port.filter) 221 return; 222 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); 226 } 227 port.queued_messages.clear(); 228 } 229 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()); 233 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; 240 } 241 } 242 message_ports_.erase(erase_item); 243 } 244 245 } // namespace content 246