Home | History | Annotate | Download | only in browser
      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