Home | History | Annotate | Download | only in messaging
      1 // Copyright (c) 2012 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 "chrome/browser/extensions/api/messaging/message_service.h"
      6 
      7 #include "base/atomic_sequence_num.h"
      8 #include "base/bind.h"
      9 #include "base/callback.h"
     10 #include "base/json/json_writer.h"
     11 #include "base/lazy_instance.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/stl_util.h"
     14 #include "base/values.h"
     15 #include "chrome/browser/chrome_notification_types.h"
     16 #include "chrome/browser/extensions/api/messaging/extension_message_port.h"
     17 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
     18 #include "chrome/browser/extensions/api/messaging/native_message_port.h"
     19 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
     20 #include "chrome/browser/extensions/extension_service.h"
     21 #include "chrome/browser/extensions/extension_tab_util.h"
     22 #include "chrome/browser/extensions/extension_util.h"
     23 #include "chrome/browser/profiles/profile.h"
     24 #include "chrome/browser/tab_contents/tab_util.h"
     25 #include "content/public/browser/notification_service.h"
     26 #include "content/public/browser/render_process_host.h"
     27 #include "content/public/browser/render_view_host.h"
     28 #include "content/public/browser/render_widget_host.h"
     29 #include "content/public/browser/render_widget_host_view.h"
     30 #include "content/public/browser/site_instance.h"
     31 #include "content/public/browser/web_contents.h"
     32 #include "extensions/browser/extension_host.h"
     33 #include "extensions/browser/extension_system.h"
     34 #include "extensions/browser/extensions_browser_client.h"
     35 #include "extensions/browser/lazy_background_task_queue.h"
     36 #include "extensions/browser/process_manager.h"
     37 #include "extensions/common/extension.h"
     38 #include "extensions/common/manifest_constants.h"
     39 #include "extensions/common/manifest_handlers/background_info.h"
     40 #include "extensions/common/manifest_handlers/externally_connectable.h"
     41 #include "extensions/common/manifest_handlers/incognito_info.h"
     42 #include "extensions/common/permissions/permissions_data.h"
     43 #include "net/base/completion_callback.h"
     44 #include "url/gurl.h"
     45 
     46 using content::BrowserContext;
     47 using content::SiteInstance;
     48 using content::WebContents;
     49 
     50 // Since we have 2 ports for every channel, we just index channels by half the
     51 // port ID.
     52 #define GET_CHANNEL_ID(port_id) ((port_id) / 2)
     53 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
     54 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
     55 
     56 // Port1 is always even, port2 is always odd.
     57 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
     58 
     59 // Change even to odd and vice versa, to get the other side of a given channel.
     60 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
     61 
     62 namespace extensions {
     63 
     64 const char kReceivingEndDoesntExistError[] =
     65     "Could not establish connection. Receiving end does not exist.";
     66 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
     67 const char kMissingPermissionError[] =
     68     "Access to native messaging requires nativeMessaging permission.";
     69 const char kProhibitedByPoliciesError[] =
     70     "Access to the native messaging host was disabled by the system "
     71     "administrator.";
     72 #endif
     73 
     74 struct MessageService::MessageChannel {
     75   scoped_ptr<MessagePort> opener;
     76   scoped_ptr<MessagePort> receiver;
     77 };
     78 
     79 struct MessageService::OpenChannelParams {
     80   content::RenderProcessHost* source;
     81   base::DictionaryValue source_tab;
     82   scoped_ptr<MessagePort> receiver;
     83   int receiver_port_id;
     84   std::string source_extension_id;
     85   std::string target_extension_id;
     86   GURL source_url;
     87   std::string channel_name;
     88   bool include_tls_channel_id;
     89   std::string tls_channel_id;
     90 
     91   // Takes ownership of receiver.
     92   OpenChannelParams(content::RenderProcessHost* source,
     93                     scoped_ptr<base::DictionaryValue> source_tab,
     94                     MessagePort* receiver,
     95                     int receiver_port_id,
     96                     const std::string& source_extension_id,
     97                     const std::string& target_extension_id,
     98                     const GURL& source_url,
     99                     const std::string& channel_name,
    100                     bool include_tls_channel_id)
    101       : source(source),
    102         receiver(receiver),
    103         receiver_port_id(receiver_port_id),
    104         source_extension_id(source_extension_id),
    105         target_extension_id(target_extension_id),
    106         source_url(source_url),
    107         channel_name(channel_name),
    108         include_tls_channel_id(include_tls_channel_id) {
    109     if (source_tab)
    110       this->source_tab.Swap(source_tab.get());
    111   }
    112 
    113  private:
    114   DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
    115 };
    116 
    117 namespace {
    118 
    119 static base::StaticAtomicSequenceNumber g_next_channel_id;
    120 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count;
    121 
    122 static content::RenderProcessHost* GetExtensionProcess(
    123     BrowserContext* context,
    124     const std::string& extension_id) {
    125   SiteInstance* site_instance =
    126       ExtensionSystem::Get(context)->process_manager()->GetSiteInstanceForURL(
    127           Extension::GetBaseURLFromExtensionId(extension_id));
    128   return site_instance->HasProcess() ? site_instance->GetProcess() : NULL;
    129 }
    130 
    131 }  // namespace
    132 
    133 content::RenderProcessHost*
    134     MessageService::MessagePort::GetRenderProcessHost() {
    135   return NULL;
    136 }
    137 
    138 // static
    139 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
    140   unsigned channel_id =
    141       static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
    142 
    143   if (channel_id == 0) {
    144     int overflow_count = g_channel_id_overflow_count.GetNext();
    145     if (overflow_count > 0)
    146       UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true);
    147   }
    148 
    149   unsigned port1_id = channel_id * 2;
    150   unsigned port2_id = channel_id * 2 + 1;
    151 
    152   // Sanity checks to make sure our channel<->port converters are correct.
    153   DCHECK(IS_OPENER_PORT_ID(port1_id));
    154   DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id), port2_id);
    155   DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id), port1_id);
    156   DCHECK_EQ(GET_CHANNEL_ID(port1_id), GET_CHANNEL_ID(port2_id));
    157   DCHECK_EQ(GET_CHANNEL_ID(port1_id), channel_id);
    158   DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id), port1_id);
    159   DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id), port2_id);
    160 
    161   *port1 = port1_id;
    162   *port2 = port2_id;
    163 }
    164 
    165 MessageService::MessageService(BrowserContext* context)
    166     : lazy_background_task_queue_(
    167           ExtensionSystem::Get(context)->lazy_background_task_queue()),
    168       weak_factory_(this) {
    169   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
    170                  content::NotificationService::AllBrowserContextsAndSources());
    171   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
    172                  content::NotificationService::AllBrowserContextsAndSources());
    173 }
    174 
    175 MessageService::~MessageService() {
    176   STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
    177   channels_.clear();
    178 }
    179 
    180 static base::LazyInstance<BrowserContextKeyedAPIFactory<MessageService> >
    181     g_factory = LAZY_INSTANCE_INITIALIZER;
    182 
    183 // static
    184 BrowserContextKeyedAPIFactory<MessageService>*
    185 MessageService::GetFactoryInstance() {
    186   return g_factory.Pointer();
    187 }
    188 
    189 // static
    190 MessageService* MessageService::Get(BrowserContext* context) {
    191   return BrowserContextKeyedAPIFactory<MessageService>::Get(context);
    192 }
    193 
    194 void MessageService::OpenChannelToExtension(
    195     int source_process_id, int source_routing_id, int receiver_port_id,
    196     const std::string& source_extension_id,
    197     const std::string& target_extension_id,
    198     const GURL& source_url,
    199     const std::string& channel_name,
    200     bool include_tls_channel_id) {
    201   content::RenderProcessHost* source =
    202       content::RenderProcessHost::FromID(source_process_id);
    203   if (!source)
    204     return;
    205   BrowserContext* context = source->GetBrowserContext();
    206 
    207   ExtensionSystem* extension_system = ExtensionSystem::Get(context);
    208   DCHECK(extension_system);
    209   const Extension* target_extension = extension_system->extension_service()->
    210       extensions()->GetByID(target_extension_id);
    211   if (!target_extension) {
    212     DispatchOnDisconnect(
    213         source, receiver_port_id, kReceivingEndDoesntExistError);
    214     return;
    215   }
    216 
    217   bool is_web_connection = false;
    218 
    219   if (source_extension_id != target_extension_id) {
    220     // It's an external connection. Check the externally_connectable manifest
    221     // key if it's present. If it's not, we allow connection from any extension
    222     // but not webpages.
    223     ExternallyConnectableInfo* externally_connectable =
    224         static_cast<ExternallyConnectableInfo*>(
    225             target_extension->GetManifestData(
    226                 manifest_keys::kExternallyConnectable));
    227     bool is_externally_connectable = false;
    228 
    229     if (externally_connectable) {
    230       if (source_extension_id.empty()) {
    231         // No source extension ID so the source was a web page. Check that the
    232         // URL matches.
    233         is_web_connection = true;
    234         is_externally_connectable =
    235             externally_connectable->matches.MatchesURL(source_url);
    236         // Only include the TLS channel ID for externally connected web pages.
    237         include_tls_channel_id &=
    238             is_externally_connectable &&
    239             externally_connectable->accepts_tls_channel_id;
    240       } else {
    241         // Source extension ID so the source was an extension. Check that the
    242         // extension matches.
    243         is_externally_connectable =
    244             externally_connectable->IdCanConnect(source_extension_id);
    245       }
    246     } else {
    247       // Default behaviour. Any extension, no webpages.
    248       is_externally_connectable = !source_extension_id.empty();
    249     }
    250 
    251     if (!is_externally_connectable) {
    252       // Important: use kReceivingEndDoesntExistError here so that we don't
    253       // leak information about this extension to callers. This way it's
    254       // indistinguishable from the extension just not existing.
    255       DispatchOnDisconnect(
    256           source, receiver_port_id, kReceivingEndDoesntExistError);
    257       return;
    258     }
    259   }
    260 
    261   WebContents* source_contents = tab_util::GetWebContentsByID(
    262       source_process_id, source_routing_id);
    263 
    264   if (context->IsOffTheRecord() &&
    265       !util::IsIncognitoEnabled(target_extension_id, context)) {
    266     // Give the user a chance to accept an incognito connection from the web if
    267     // they haven't already, with the conditions:
    268     // - Only for spanning-mode incognito. We don't want the complication of
    269     //   spinning up an additional process here which might need to do some
    270     //   setup that we're not expecting.
    271     // - Only for extensions that can't normally be enabled in incognito, since
    272     //   that surface (e.g. chrome://extensions) should be the only one for
    273     //   enabling in incognito. In practice this means platform apps only.
    274     if (!is_web_connection || IncognitoInfo::IsSplitMode(target_extension) ||
    275         target_extension->can_be_incognito_enabled() ||
    276         // This check may show a dialog.
    277         !IncognitoConnectability::Get(context)
    278              ->Query(target_extension, source_contents, source_url)) {
    279       DispatchOnDisconnect(
    280           source, receiver_port_id, kReceivingEndDoesntExistError);
    281       return;
    282     }
    283   }
    284 
    285   // Note: we use the source's profile here. If the source is an incognito
    286   // process, we will use the incognito EPM to find the right extension process,
    287   // which depends on whether the extension uses spanning or split mode.
    288   MessagePort* receiver = new ExtensionMessagePort(
    289       GetExtensionProcess(context, target_extension_id),
    290       MSG_ROUTING_CONTROL,
    291       target_extension_id);
    292 
    293   // Include info about the opener's tab (if it was a tab).
    294   scoped_ptr<base::DictionaryValue> source_tab;
    295   GURL source_url_for_tab;
    296 
    297   if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
    298     // Only the tab id is useful to platform apps for internal use. The
    299     // unnecessary bits will be stripped out in
    300     // MessagingBindings::DispatchOnConnect().
    301     source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
    302     source_url_for_tab = source_url;
    303   }
    304 
    305   OpenChannelParams* params = new OpenChannelParams(source,
    306                                                     source_tab.Pass(),
    307                                                     receiver,
    308                                                     receiver_port_id,
    309                                                     source_extension_id,
    310                                                     target_extension_id,
    311                                                     source_url_for_tab,
    312                                                     channel_name,
    313                                                     include_tls_channel_id);
    314 
    315   // If the target requests the TLS channel id, begin the lookup for it.
    316   // The target might also be a lazy background page, checked next, but the
    317   // loading of lazy background pages continues asynchronously, so enqueue
    318   // messages awaiting TLS channel ID first.
    319   if (include_tls_channel_id) {
    320     pending_tls_channel_id_channels_[GET_CHANNEL_ID(params->receiver_port_id)]
    321         = PendingMessagesQueue();
    322     property_provider_.GetChannelID(
    323         Profile::FromBrowserContext(context),
    324         source_url,
    325         base::Bind(&MessageService::GotChannelID,
    326                    weak_factory_.GetWeakPtr(),
    327                    base::Passed(make_scoped_ptr(params))));
    328     return;
    329   }
    330 
    331   // The target might be a lazy background page. In that case, we have to check
    332   // if it is loaded and ready, and if not, queue up the task and load the
    333   // page.
    334   if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
    335           context, target_extension, params)) {
    336     return;
    337   }
    338 
    339   OpenChannelImpl(make_scoped_ptr(params));
    340 }
    341 
    342 void MessageService::OpenChannelToNativeApp(
    343     int source_process_id,
    344     int source_routing_id,
    345     int receiver_port_id,
    346     const std::string& source_extension_id,
    347     const std::string& native_app_name) {
    348   content::RenderProcessHost* source =
    349       content::RenderProcessHost::FromID(source_process_id);
    350   if (!source)
    351     return;
    352 
    353 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
    354   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
    355   ExtensionService* extension_service =
    356       ExtensionSystem::Get(profile)->extension_service();
    357   bool has_permission = false;
    358   if (extension_service) {
    359     const Extension* extension =
    360         extension_service->GetExtensionById(source_extension_id, false);
    361     has_permission = extension &&
    362                      extension->permissions_data()->HasAPIPermission(
    363                          APIPermission::kNativeMessaging);
    364   }
    365 
    366   if (!has_permission) {
    367     DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
    368     return;
    369   }
    370 
    371   PrefService* pref_service = profile->GetPrefs();
    372 
    373   // Verify that the host is not blocked by policies.
    374   NativeMessageProcessHost::PolicyPermission policy_permission =
    375       NativeMessageProcessHost::IsHostAllowed(pref_service, native_app_name);
    376   if (policy_permission == NativeMessageProcessHost::DISALLOW) {
    377     DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError);
    378     return;
    379   }
    380 
    381   scoped_ptr<MessageChannel> channel(new MessageChannel());
    382   channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
    383                                                  source_extension_id));
    384 
    385   // Get handle of the native view and pass it to the native messaging host.
    386   gfx::NativeView native_view =
    387       content::RenderWidgetHost::FromID(source_process_id, source_routing_id)->
    388           GetView()->GetNativeView();
    389 
    390   scoped_ptr<NativeMessageProcessHost> native_process =
    391       NativeMessageProcessHost::Create(
    392           native_view,
    393           base::WeakPtr<NativeMessageProcessHost::Client>(
    394               weak_factory_.GetWeakPtr()),
    395           source_extension_id, native_app_name, receiver_port_id,
    396           policy_permission == NativeMessageProcessHost::ALLOW_ALL);
    397 
    398   // Abandon the channel.
    399   if (!native_process.get()) {
    400     LOG(ERROR) << "Failed to create native process.";
    401     DispatchOnDisconnect(
    402         source, receiver_port_id, kReceivingEndDoesntExistError);
    403     return;
    404   }
    405   channel->receiver.reset(new NativeMessagePort(native_process.release()));
    406 
    407   // Keep the opener alive until the channel is closed.
    408   channel->opener->IncrementLazyKeepaliveCount();
    409 
    410   AddChannel(channel.release(), receiver_port_id);
    411 #else  // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
    412   const char kNativeMessagingNotSupportedError[] =
    413       "Native Messaging is not supported on this platform.";
    414   DispatchOnDisconnect(
    415       source, receiver_port_id, kNativeMessagingNotSupportedError);
    416 #endif  // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
    417 }
    418 
    419 void MessageService::OpenChannelToTab(
    420     int source_process_id, int source_routing_id, int receiver_port_id,
    421     int tab_id, const std::string& extension_id,
    422     const std::string& channel_name) {
    423   content::RenderProcessHost* source =
    424       content::RenderProcessHost::FromID(source_process_id);
    425   if (!source)
    426     return;
    427   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
    428 
    429   WebContents* contents = NULL;
    430   scoped_ptr<MessagePort> receiver;
    431   if (ExtensionTabUtil::GetTabById(tab_id, profile, true,
    432                                    NULL, NULL, &contents, NULL)) {
    433     receiver.reset(new ExtensionMessagePort(
    434         contents->GetRenderProcessHost(),
    435         contents->GetRenderViewHost()->GetRoutingID(),
    436         extension_id));
    437   }
    438 
    439   if (contents && contents->GetController().NeedsReload()) {
    440     // The tab isn't loaded yet. Don't attempt to connect.
    441     DispatchOnDisconnect(
    442         source, receiver_port_id, kReceivingEndDoesntExistError);
    443     return;
    444   }
    445 
    446   scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
    447         source,
    448         scoped_ptr<base::DictionaryValue>(),  // Source tab doesn't make sense
    449                                               // for opening to tabs.
    450         receiver.release(),
    451         receiver_port_id,
    452         extension_id,
    453         extension_id,
    454         GURL(),  // Source URL doesn't make sense for opening to tabs.
    455         channel_name,
    456         false));  // Connections to tabs don't get TLS channel IDs.
    457   OpenChannelImpl(params.Pass());
    458 }
    459 
    460 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
    461   if (!params->source)
    462     return false;  // Closed while in flight.
    463 
    464   if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
    465     DispatchOnDisconnect(params->source,
    466                          params->receiver_port_id,
    467                          kReceivingEndDoesntExistError);
    468     return false;
    469   }
    470 
    471   // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
    472   // http://code.google.com/p/chromium/issues/detail?id=19067
    473   CHECK(params->receiver->GetRenderProcessHost());
    474 
    475   MessageChannel* channel(new MessageChannel);
    476   channel->opener.reset(new ExtensionMessagePort(params->source,
    477                                                  MSG_ROUTING_CONTROL,
    478                                                  params->source_extension_id));
    479   channel->receiver.reset(params->receiver.release());
    480 
    481   CHECK(channel->receiver->GetRenderProcessHost());
    482 
    483   AddChannel(channel, params->receiver_port_id);
    484 
    485   CHECK(channel->receiver->GetRenderProcessHost());
    486 
    487   // Send the connect event to the receiver.  Give it the opener's port ID (the
    488   // opener has the opposite port ID).
    489   channel->receiver->DispatchOnConnect(params->receiver_port_id,
    490                                        params->channel_name,
    491                                        params->source_tab,
    492                                        params->source_extension_id,
    493                                        params->target_extension_id,
    494                                        params->source_url,
    495                                        params->tls_channel_id);
    496 
    497   // Keep both ends of the channel alive until the channel is closed.
    498   channel->opener->IncrementLazyKeepaliveCount();
    499   channel->receiver->IncrementLazyKeepaliveCount();
    500   return true;
    501 }
    502 
    503 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
    504   int channel_id = GET_CHANNEL_ID(receiver_port_id);
    505   CHECK(channels_.find(channel_id) == channels_.end());
    506   channels_[channel_id] = channel;
    507   pending_lazy_background_page_channels_.erase(channel_id);
    508 }
    509 
    510 void MessageService::CloseChannel(int port_id,
    511                                   const std::string& error_message) {
    512   // Note: The channel might be gone already, if the other side closed first.
    513   int channel_id = GET_CHANNEL_ID(port_id);
    514   MessageChannelMap::iterator it = channels_.find(channel_id);
    515   if (it == channels_.end()) {
    516     PendingLazyBackgroundPageChannelMap::iterator pending =
    517         pending_lazy_background_page_channels_.find(channel_id);
    518     if (pending != pending_lazy_background_page_channels_.end()) {
    519       lazy_background_task_queue_->AddPendingTask(
    520           pending->second.first, pending->second.second,
    521           base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel,
    522                      weak_factory_.GetWeakPtr(), port_id, error_message));
    523     }
    524     return;
    525   }
    526   CloseChannelImpl(it, port_id, error_message, true);
    527 }
    528 
    529 void MessageService::CloseChannelImpl(
    530     MessageChannelMap::iterator channel_iter,
    531     int closing_port_id,
    532     const std::string& error_message,
    533     bool notify_other_port) {
    534   MessageChannel* channel = channel_iter->second;
    535 
    536   // Notify the other side.
    537   if (notify_other_port) {
    538     MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
    539         channel->receiver.get() : channel->opener.get();
    540     port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
    541                                error_message);
    542   }
    543 
    544   // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
    545   channel->opener->DecrementLazyKeepaliveCount();
    546   channel->receiver->DecrementLazyKeepaliveCount();
    547 
    548   delete channel_iter->second;
    549   channels_.erase(channel_iter);
    550 }
    551 
    552 void MessageService::PostMessage(int source_port_id, const Message& message) {
    553   int channel_id = GET_CHANNEL_ID(source_port_id);
    554   MessageChannelMap::iterator iter = channels_.find(channel_id);
    555   if (iter == channels_.end()) {
    556     // If this channel is pending, queue up the PostMessage to run once
    557     // the channel opens.
    558     EnqueuePendingMessage(source_port_id, channel_id, message);
    559     return;
    560   }
    561 
    562   DispatchMessage(source_port_id, iter->second, message);
    563 }
    564 
    565 void MessageService::PostMessageFromNativeProcess(int port_id,
    566                                                   const std::string& message) {
    567   PostMessage(port_id, Message(message, false /* user_gesture */));
    568 }
    569 
    570 void MessageService::Observe(int type,
    571                              const content::NotificationSource& source,
    572                              const content::NotificationDetails& details) {
    573   switch (type) {
    574     case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
    575     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
    576       content::RenderProcessHost* renderer =
    577           content::Source<content::RenderProcessHost>(source).ptr();
    578       OnProcessClosed(renderer);
    579       break;
    580     }
    581     default:
    582       NOTREACHED();
    583       return;
    584   }
    585 }
    586 
    587 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
    588   // Close any channels that share this renderer.  We notify the opposite
    589   // port that his pair has closed.
    590   for (MessageChannelMap::iterator it = channels_.begin();
    591        it != channels_.end(); ) {
    592     MessageChannelMap::iterator current = it++;
    593 
    594     content::RenderProcessHost* opener_process =
    595         current->second->opener->GetRenderProcessHost();
    596     content::RenderProcessHost* receiver_process =
    597         current->second->receiver->GetRenderProcessHost();
    598 
    599     // Only notify the other side if it has a different porocess host.
    600     bool notify_other_port = opener_process && receiver_process &&
    601         opener_process != receiver_process;
    602 
    603     if (opener_process == process) {
    604       CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
    605                        std::string(), notify_other_port);
    606     } else if (receiver_process == process) {
    607       CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
    608                        std::string(), notify_other_port);
    609     }
    610   }
    611 }
    612 
    613 void MessageService::EnqueuePendingMessage(int source_port_id,
    614                                            int channel_id,
    615                                            const Message& message) {
    616   PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
    617       pending_tls_channel_id_channels_.find(channel_id);
    618   if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
    619     pending_for_tls_channel_id->second.push_back(
    620         PendingMessage(source_port_id, message));
    621     // Pending messages must only be pending the TLS channel ID or lazy
    622     // background page loading, never both.
    623     return;
    624   }
    625   EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
    626                                              channel_id,
    627                                              message);
    628 }
    629 
    630 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
    631     int source_port_id,
    632     int channel_id,
    633     const Message& message) {
    634   PendingLazyBackgroundPageChannelMap::iterator pending =
    635       pending_lazy_background_page_channels_.find(channel_id);
    636   if (pending != pending_lazy_background_page_channels_.end()) {
    637     lazy_background_task_queue_->AddPendingTask(
    638         pending->second.first, pending->second.second,
    639         base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage,
    640                    weak_factory_.GetWeakPtr(), source_port_id, message));
    641   }
    642 }
    643 
    644 void MessageService::DispatchMessage(int source_port_id,
    645                                      MessageChannel* channel,
    646                                      const Message& message) {
    647   // Figure out which port the ID corresponds to.
    648   int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
    649   MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
    650       channel->opener.get() : channel->receiver.get();
    651 
    652   port->DispatchOnMessage(message, dest_port_id);
    653 }
    654 
    655 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
    656     BrowserContext* context,
    657     const Extension* extension,
    658     OpenChannelParams* params) {
    659   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
    660     return false;
    661 
    662   // If the extension uses spanning incognito mode, make sure we're always
    663   // using the original profile since that is what the extension process
    664   // will use.
    665   if (!IncognitoInfo::IsSplitMode(extension))
    666     context = ExtensionsBrowserClient::Get()->GetOriginalContext(context);
    667 
    668   if (!lazy_background_task_queue_->ShouldEnqueueTask(context, extension))
    669     return false;
    670 
    671   pending_lazy_background_page_channels_
    672       [GET_CHANNEL_ID(params->receiver_port_id)] =
    673           PendingLazyBackgroundPageChannel(context, extension->id());
    674   scoped_ptr<OpenChannelParams> scoped_params(params);
    675   lazy_background_task_queue_->AddPendingTask(
    676       context,
    677       extension->id(),
    678       base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel,
    679                  weak_factory_.GetWeakPtr(),
    680                  base::Passed(&scoped_params),
    681                  params->source->GetID()));
    682   return true;
    683 }
    684 
    685 void MessageService::GotChannelID(scoped_ptr<OpenChannelParams> params,
    686                                   const std::string& tls_channel_id) {
    687   params->tls_channel_id.assign(tls_channel_id);
    688   int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
    689 
    690   PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
    691       pending_tls_channel_id_channels_.find(channel_id);
    692   if (pending_for_tls_channel_id == pending_tls_channel_id_channels_.end()) {
    693     NOTREACHED();
    694     return;
    695   }
    696 
    697   BrowserContext* context = params->source->GetBrowserContext();
    698 
    699   const Extension* target_extension =
    700       ExtensionSystem::Get(context)->extension_service()->extensions()->GetByID(
    701           params->target_extension_id);
    702   if (!target_extension) {
    703     pending_tls_channel_id_channels_.erase(channel_id);
    704     DispatchOnDisconnect(
    705         params->source, params->receiver_port_id,
    706         kReceivingEndDoesntExistError);
    707     return;
    708   }
    709   PendingMessagesQueue& pending_messages = pending_for_tls_channel_id->second;
    710   if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
    711           context, target_extension, params.get())) {
    712     // Lazy background queue took ownership. Release ours.
    713     ignore_result(params.release());
    714     // Messages queued up waiting for the TLS channel ID now need to be queued
    715     // up for the lazy background page to load.
    716     for (PendingMessagesQueue::iterator it = pending_messages.begin();
    717          it != pending_messages.end();
    718          it++) {
    719       EnqueuePendingMessageForLazyBackgroundLoad(it->first, channel_id,
    720                                                  it->second);
    721     }
    722   } else {
    723     OpenChannelImpl(params.Pass());
    724     // Messages queued up waiting for the TLS channel ID can be posted now.
    725     MessageChannelMap::iterator channel_iter = channels_.find(channel_id);
    726     if (channel_iter != channels_.end()) {
    727       for (PendingMessagesQueue::iterator it = pending_messages.begin();
    728            it != pending_messages.end();
    729            it++) {
    730         DispatchMessage(it->first, channel_iter->second, it->second);
    731       }
    732     }
    733   }
    734   pending_tls_channel_id_channels_.erase(channel_id);
    735 }
    736 
    737 void MessageService::PendingLazyBackgroundPageOpenChannel(
    738     scoped_ptr<OpenChannelParams> params,
    739     int source_process_id,
    740     ExtensionHost* host) {
    741   if (!host)
    742     return;  // TODO(mpcomplete): notify source of disconnect?
    743 
    744   // Re-lookup the source process since it may no longer be valid.
    745   content::RenderProcessHost* source =
    746       content::RenderProcessHost::FromID(source_process_id);
    747   if (!source)
    748     return;
    749 
    750   params->source = source;
    751   params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
    752                                                   MSG_ROUTING_CONTROL,
    753                                                   params->target_extension_id));
    754   OpenChannelImpl(params.Pass());
    755 }
    756 
    757 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
    758                                           int port_id,
    759                                           const std::string& error_message) {
    760   ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
    761   port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
    762 }
    763 
    764 }  // namespace extensions
    765