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/native_message_port.h"
     18 #include "chrome/browser/extensions/extension_host.h"
     19 #include "chrome/browser/extensions/extension_process_manager.h"
     20 #include "chrome/browser/extensions/extension_service.h"
     21 #include "chrome/browser/extensions/extension_system.h"
     22 #include "chrome/browser/extensions/extension_tab_util.h"
     23 #include "chrome/browser/extensions/lazy_background_task_queue.h"
     24 #include "chrome/browser/extensions/process_map.h"
     25 #include "chrome/browser/profiles/profile.h"
     26 #include "chrome/browser/tab_contents/tab_util.h"
     27 #include "chrome/common/extensions/background_info.h"
     28 #include "chrome/common/extensions/extension.h"
     29 #include "chrome/common/extensions/extension_manifest_constants.h"
     30 #include "chrome/common/extensions/extension_messages.h"
     31 #include "chrome/common/extensions/incognito_handler.h"
     32 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
     33 #include "content/public/browser/browser_thread.h"
     34 #include "content/public/browser/notification_service.h"
     35 #include "content/public/browser/render_process_host.h"
     36 #include "content/public/browser/render_view_host.h"
     37 #include "content/public/browser/render_widget_host.h"
     38 #include "content/public/browser/render_widget_host_view.h"
     39 #include "content/public/browser/site_instance.h"
     40 #include "content/public/browser/web_contents.h"
     41 #include "url/gurl.h"
     42 
     43 using content::SiteInstance;
     44 using content::WebContents;
     45 
     46 // Since we have 2 ports for every channel, we just index channels by half the
     47 // port ID.
     48 #define GET_CHANNEL_ID(port_id) ((port_id) / 2)
     49 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
     50 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
     51 
     52 // Port1 is always even, port2 is always odd.
     53 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
     54 
     55 // Change even to odd and vice versa, to get the other side of a given channel.
     56 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
     57 
     58 namespace extensions {
     59 
     60 namespace {
     61 const char kReceivingEndDoesntExistError[] =
     62     "Could not establish connection. Receiving end does not exist.";
     63 const char kMissingPermissionError[] =
     64     "Access to native messaging requires nativeMessaging permission.";
     65 const char kNativeMessagingNotSupportedError[] =
     66     "Native Messaging is not supported on this platform.";
     67 }
     68 
     69 struct MessageService::MessageChannel {
     70   scoped_ptr<MessagePort> opener;
     71   scoped_ptr<MessagePort> receiver;
     72 };
     73 
     74 struct MessageService::OpenChannelParams {
     75   content::RenderProcessHost* source;
     76   base::DictionaryValue source_tab;
     77   scoped_ptr<MessagePort> receiver;
     78   int receiver_port_id;
     79   std::string source_extension_id;
     80   std::string target_extension_id;
     81   GURL source_url;
     82   std::string channel_name;
     83 
     84   // Takes ownership of receiver.
     85   OpenChannelParams(content::RenderProcessHost* source,
     86                     scoped_ptr<base::DictionaryValue> source_tab,
     87                     MessagePort* receiver,
     88                     int receiver_port_id,
     89                     const std::string& source_extension_id,
     90                     const std::string& target_extension_id,
     91                     const GURL& source_url,
     92                     const std::string& channel_name)
     93       : source(source),
     94         receiver(receiver),
     95         receiver_port_id(receiver_port_id),
     96         source_extension_id(source_extension_id),
     97         target_extension_id(target_extension_id),
     98         source_url(source_url),
     99         channel_name(channel_name) {
    100     if (source_tab)
    101       this->source_tab.Swap(source_tab.get());
    102   }
    103 
    104  private:
    105   DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
    106 };
    107 
    108 namespace {
    109 
    110 static base::StaticAtomicSequenceNumber g_next_channel_id;
    111 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count;
    112 
    113 static content::RenderProcessHost* GetExtensionProcess(
    114     Profile* profile, const std::string& extension_id) {
    115   SiteInstance* site_instance =
    116       extensions::ExtensionSystem::Get(profile)->process_manager()->
    117           GetSiteInstanceForURL(
    118               Extension::GetBaseURLFromExtensionId(extension_id));
    119 
    120   if (!site_instance->HasProcess())
    121     return NULL;
    122 
    123   return site_instance->GetProcess();
    124 }
    125 
    126 }  // namespace
    127 
    128 content::RenderProcessHost*
    129     MessageService::MessagePort::GetRenderProcessHost() {
    130   return NULL;
    131 }
    132 
    133 // static
    134 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
    135   unsigned channel_id =
    136       static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
    137 
    138   if (channel_id == 0) {
    139     int overflow_count = g_channel_id_overflow_count.GetNext();
    140     if (overflow_count > 0)
    141       UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true);
    142   }
    143 
    144   unsigned port1_id = channel_id * 2;
    145   unsigned port2_id = channel_id * 2 + 1;
    146 
    147   // Sanity checks to make sure our channel<->port converters are correct.
    148   DCHECK(IS_OPENER_PORT_ID(port1_id));
    149   DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id);
    150   DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id);
    151   DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id));
    152   DCHECK(GET_CHANNEL_ID(port1_id) == channel_id);
    153   DCHECK(GET_CHANNEL_OPENER_ID(channel_id) == port1_id);
    154   DCHECK(GET_CHANNEL_RECEIVERS_ID(channel_id) == port2_id);
    155 
    156   *port1 = port1_id;
    157   *port2 = port2_id;
    158 }
    159 
    160 MessageService::MessageService(Profile* profile)
    161     : lazy_background_task_queue_(
    162           ExtensionSystem::Get(profile)->lazy_background_task_queue()),
    163       weak_factory_(this) {
    164   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
    165                  content::NotificationService::AllBrowserContextsAndSources());
    166   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
    167                  content::NotificationService::AllBrowserContextsAndSources());
    168 }
    169 
    170 MessageService::~MessageService() {
    171   STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
    172   channels_.clear();
    173 }
    174 
    175 static base::LazyInstance<ProfileKeyedAPIFactory<MessageService> >
    176 g_factory = LAZY_INSTANCE_INITIALIZER;
    177 
    178 // static
    179 ProfileKeyedAPIFactory<MessageService>* MessageService::GetFactoryInstance() {
    180   return &g_factory.Get();
    181 }
    182 
    183 // static
    184 MessageService* MessageService::Get(Profile* profile) {
    185   return ProfileKeyedAPIFactory<MessageService>::GetForProfile(profile);
    186 }
    187 
    188 void MessageService::OpenChannelToExtension(
    189     int source_process_id, int source_routing_id, int receiver_port_id,
    190     const std::string& source_extension_id,
    191     const std::string& target_extension_id,
    192     const GURL& source_url,
    193     const std::string& channel_name) {
    194   content::RenderProcessHost* source =
    195       content::RenderProcessHost::FromID(source_process_id);
    196   if (!source)
    197     return;
    198   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
    199 
    200   const Extension* target_extension = ExtensionSystem::Get(profile)->
    201       extension_service()->extensions()->GetByID(target_extension_id);
    202   if (!target_extension) {
    203     DispatchOnDisconnect(
    204         source, receiver_port_id, kReceivingEndDoesntExistError);
    205     return;
    206   }
    207 
    208   ExtensionService* extension_service =
    209       extensions::ExtensionSystem::Get(profile)->extension_service();
    210 
    211   if (profile->IsOffTheRecord() &&
    212       !extension_service->IsIncognitoEnabled(target_extension_id)) {
    213     DispatchOnDisconnect(
    214         source, receiver_port_id, kReceivingEndDoesntExistError);
    215     return;
    216   }
    217 
    218   if (source_extension_id != target_extension_id) {
    219     // It's an external connection. Check the externally_connectable manifest
    220     // key if it's present. If it's not, we allow connection from any extension
    221     // but not webpages.
    222     ExternallyConnectableInfo* externally_connectable =
    223         static_cast<ExternallyConnectableInfo*>(
    224             target_extension->GetManifestData(
    225                 extension_manifest_keys::kExternallyConnectable));
    226     bool is_externally_connectable = false;
    227 
    228     if (externally_connectable) {
    229       if (source_extension_id.empty()) {
    230         // No source extension ID so the source was a web page. Check that the
    231         // URL matches.
    232         is_externally_connectable =
    233             externally_connectable->matches.MatchesURL(source_url);
    234       } else {
    235         // Source extension ID so the source was an extension. Check that the
    236         // extension matches.
    237         is_externally_connectable =
    238             externally_connectable->IdCanConnect(source_extension_id);
    239       }
    240     } else {
    241       // Default behaviour. Any extension, no webpages.
    242       is_externally_connectable = !source_extension_id.empty();
    243     }
    244 
    245     if (!is_externally_connectable) {
    246       // Important: use kReceivingEndDoesntExistError here so that we don't
    247       // leak information about this extension to callers. This way it's
    248       // indistinguishable from the extension just not existing.
    249       DispatchOnDisconnect(
    250           source, receiver_port_id, kReceivingEndDoesntExistError);
    251       return;
    252     }
    253   }
    254 
    255   // Note: we use the source's profile here. If the source is an incognito
    256   // process, we will use the incognito EPM to find the right extension process,
    257   // which depends on whether the extension uses spanning or split mode.
    258   MessagePort* receiver = new ExtensionMessagePort(
    259       GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL,
    260       target_extension_id);
    261   WebContents* source_contents = tab_util::GetWebContentsByID(
    262       source_process_id, source_routing_id);
    263 
    264   // Include info about the opener's tab (if it was a tab).
    265   scoped_ptr<base::DictionaryValue> source_tab;
    266   GURL source_url_for_tab;
    267 
    268   if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
    269     // Platform apps can be sent messages, but don't have a Tab concept.
    270     if (!target_extension->is_platform_app())
    271       source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
    272     source_url_for_tab = source_url;
    273   }
    274 
    275   OpenChannelParams* params = new OpenChannelParams(source,
    276                                                     source_tab.Pass(),
    277                                                     receiver,
    278                                                     receiver_port_id,
    279                                                     source_extension_id,
    280                                                     target_extension_id,
    281                                                     source_url_for_tab,
    282                                                     channel_name);
    283 
    284   // The target might be a lazy background page. In that case, we have to check
    285   // if it is loaded and ready, and if not, queue up the task and load the
    286   // page.
    287   if (MaybeAddPendingOpenChannelTask(profile, target_extension, params)) {
    288     return;
    289   }
    290 
    291   OpenChannelImpl(make_scoped_ptr(params));
    292 }
    293 
    294 void MessageService::OpenChannelToNativeApp(
    295     int source_process_id,
    296     int source_routing_id,
    297     int receiver_port_id,
    298     const std::string& source_extension_id,
    299     const std::string& native_app_name) {
    300   content::RenderProcessHost* source =
    301       content::RenderProcessHost::FromID(source_process_id);
    302   if (!source)
    303     return;
    304 
    305 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
    306   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
    307   ExtensionService* extension_service =
    308       extensions::ExtensionSystem::Get(profile)->extension_service();
    309   bool has_permission = false;
    310   if (extension_service) {
    311     const Extension* extension =
    312         extension_service->GetExtensionById(source_extension_id, false);
    313     has_permission = extension && extension->HasAPIPermission(
    314         APIPermission::kNativeMessaging);
    315   }
    316 
    317   if (!has_permission) {
    318     DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
    319     return;
    320   }
    321 
    322   scoped_ptr<MessageChannel> channel(new MessageChannel());
    323   channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
    324                                                  source_extension_id));
    325 
    326   // Get handle of the native view and pass it to the native messaging host.
    327   gfx::NativeView native_view =
    328       content::RenderWidgetHost::FromID(source_process_id, source_routing_id)->
    329           GetView()->GetNativeView();
    330 
    331   scoped_ptr<NativeMessageProcessHost> native_process =
    332       NativeMessageProcessHost::Create(
    333           native_view,
    334           base::WeakPtr<NativeMessageProcessHost::Client>(
    335               weak_factory_.GetWeakPtr()),
    336           source_extension_id, native_app_name, receiver_port_id);
    337 
    338   // Abandon the channel.
    339   if (!native_process.get()) {
    340     LOG(ERROR) << "Failed to create native process.";
    341     DispatchOnDisconnect(
    342         source, receiver_port_id, kReceivingEndDoesntExistError);
    343     return;
    344   }
    345   channel->receiver.reset(new NativeMessagePort(native_process.release()));
    346 
    347   // Keep the opener alive until the channel is closed.
    348   channel->opener->IncrementLazyKeepaliveCount();
    349 
    350   AddChannel(channel.release(), receiver_port_id);
    351 #else  // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
    352   DispatchOnDisconnect(
    353       source, receiver_port_id, kNativeMessagingNotSupportedError);
    354 #endif  // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
    355 }
    356 
    357 void MessageService::OpenChannelToTab(
    358     int source_process_id, int source_routing_id, int receiver_port_id,
    359     int tab_id, const std::string& extension_id,
    360     const std::string& channel_name) {
    361   content::RenderProcessHost* source =
    362       content::RenderProcessHost::FromID(source_process_id);
    363   if (!source)
    364     return;
    365   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
    366 
    367   WebContents* contents = NULL;
    368   scoped_ptr<MessagePort> receiver;
    369   if (ExtensionTabUtil::GetTabById(tab_id, profile, true,
    370                                    NULL, NULL, &contents, NULL)) {
    371     receiver.reset(new ExtensionMessagePort(
    372         contents->GetRenderProcessHost(),
    373         contents->GetRenderViewHost()->GetRoutingID(),
    374         extension_id));
    375   }
    376 
    377   if (contents && contents->GetController().NeedsReload()) {
    378     // The tab isn't loaded yet. Don't attempt to connect.
    379     DispatchOnDisconnect(
    380         source, receiver_port_id, kReceivingEndDoesntExistError);
    381     return;
    382   }
    383 
    384   scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
    385         source,
    386         scoped_ptr<base::DictionaryValue>(),  // Source tab doesn't make sense
    387                                               // for opening to tabs.
    388         receiver.release(),
    389         receiver_port_id,
    390         extension_id,
    391         extension_id,
    392         GURL(),  // Source URL doesn't make sense for opening to tabs.
    393         channel_name));
    394   OpenChannelImpl(params.Pass());
    395 }
    396 
    397 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
    398   if (!params->source)
    399     return false;  // Closed while in flight.
    400 
    401   if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
    402     DispatchOnDisconnect(params->source,
    403                          params->receiver_port_id,
    404                          kReceivingEndDoesntExistError);
    405     return false;
    406   }
    407 
    408   // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
    409   // http://code.google.com/p/chromium/issues/detail?id=19067
    410   CHECK(params->receiver->GetRenderProcessHost());
    411 
    412   MessageChannel* channel(new MessageChannel);
    413   channel->opener.reset(new ExtensionMessagePort(params->source,
    414                                                  MSG_ROUTING_CONTROL,
    415                                                  params->source_extension_id));
    416   channel->receiver.reset(params->receiver.release());
    417 
    418   CHECK(channel->receiver->GetRenderProcessHost());
    419 
    420   AddChannel(channel, params->receiver_port_id);
    421 
    422   CHECK(channel->receiver->GetRenderProcessHost());
    423 
    424   // Send the connect event to the receiver.  Give it the opener's port ID (the
    425   // opener has the opposite port ID).
    426   channel->receiver->DispatchOnConnect(params->receiver_port_id,
    427                                        params->channel_name,
    428                                        params->source_tab,
    429                                        params->source_extension_id,
    430                                        params->target_extension_id,
    431                                        params->source_url);
    432 
    433   // Keep both ends of the channel alive until the channel is closed.
    434   channel->opener->IncrementLazyKeepaliveCount();
    435   channel->receiver->IncrementLazyKeepaliveCount();
    436   return true;
    437 }
    438 
    439 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
    440   int channel_id = GET_CHANNEL_ID(receiver_port_id);
    441   CHECK(channels_.find(channel_id) == channels_.end());
    442   channels_[channel_id] = channel;
    443   pending_channels_.erase(channel_id);
    444 }
    445 
    446 void MessageService::CloseChannel(int port_id,
    447                                   const std::string& error_message) {
    448   // Note: The channel might be gone already, if the other side closed first.
    449   int channel_id = GET_CHANNEL_ID(port_id);
    450   MessageChannelMap::iterator it = channels_.find(channel_id);
    451   if (it == channels_.end()) {
    452     PendingChannelMap::iterator pending = pending_channels_.find(channel_id);
    453     if (pending != pending_channels_.end()) {
    454       lazy_background_task_queue_->AddPendingTask(
    455           pending->second.first, pending->second.second,
    456           base::Bind(&MessageService::PendingCloseChannel,
    457                      weak_factory_.GetWeakPtr(), port_id, error_message));
    458     }
    459     return;
    460   }
    461   CloseChannelImpl(it, port_id, error_message, true);
    462 }
    463 
    464 void MessageService::CloseChannelImpl(
    465     MessageChannelMap::iterator channel_iter,
    466     int closing_port_id,
    467     const std::string& error_message,
    468     bool notify_other_port) {
    469   MessageChannel* channel = channel_iter->second;
    470 
    471   // Notify the other side.
    472   if (notify_other_port) {
    473     MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
    474         channel->receiver.get() : channel->opener.get();
    475     port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
    476                                error_message);
    477   }
    478 
    479   // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
    480   channel->opener->DecrementLazyKeepaliveCount();
    481   channel->receiver->DecrementLazyKeepaliveCount();
    482 
    483   delete channel_iter->second;
    484   channels_.erase(channel_iter);
    485 }
    486 
    487 void MessageService::PostMessage(
    488     int source_port_id, const std::string& message) {
    489   int channel_id = GET_CHANNEL_ID(source_port_id);
    490   MessageChannelMap::iterator iter = channels_.find(channel_id);
    491   if (iter == channels_.end()) {
    492     // If this channel is pending, queue up the PostMessage to run once
    493     // the channel opens.
    494     PendingChannelMap::iterator pending = pending_channels_.find(channel_id);
    495     if (pending != pending_channels_.end()) {
    496       lazy_background_task_queue_->AddPendingTask(
    497           pending->second.first, pending->second.second,
    498           base::Bind(&MessageService::PendingPostMessage,
    499                      weak_factory_.GetWeakPtr(), source_port_id, message));
    500     }
    501     return;
    502   }
    503 
    504   // Figure out which port the ID corresponds to.
    505   int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
    506   MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
    507       iter->second->opener.get() : iter->second->receiver.get();
    508 
    509   port->DispatchOnMessage(message, dest_port_id);
    510 }
    511 
    512 void MessageService::PostMessageFromNativeProcess(int port_id,
    513                                                   const std::string& message) {
    514   PostMessage(port_id, message);
    515 }
    516 
    517 void MessageService::Observe(int type,
    518                              const content::NotificationSource& source,
    519                              const content::NotificationDetails& details) {
    520   switch (type) {
    521     case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
    522     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
    523       content::RenderProcessHost* renderer =
    524           content::Source<content::RenderProcessHost>(source).ptr();
    525       OnProcessClosed(renderer);
    526       break;
    527     }
    528     default:
    529       NOTREACHED();
    530       return;
    531   }
    532 }
    533 
    534 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
    535   // Close any channels that share this renderer.  We notify the opposite
    536   // port that his pair has closed.
    537   for (MessageChannelMap::iterator it = channels_.begin();
    538        it != channels_.end(); ) {
    539     MessageChannelMap::iterator current = it++;
    540 
    541     content::RenderProcessHost* opener_process =
    542         current->second->opener->GetRenderProcessHost();
    543     content::RenderProcessHost* receiver_process =
    544         current->second->receiver->GetRenderProcessHost();
    545 
    546     // Only notify the other side if it has a different porocess host.
    547     bool notify_other_port = opener_process && receiver_process &&
    548         opener_process != receiver_process;
    549 
    550     if (opener_process == process) {
    551       CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
    552                        std::string(), notify_other_port);
    553     } else if (receiver_process == process) {
    554       CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
    555                        std::string(), notify_other_port);
    556     }
    557   }
    558 }
    559 
    560 bool MessageService::MaybeAddPendingOpenChannelTask(
    561     Profile* profile,
    562     const Extension* extension,
    563     OpenChannelParams* params) {
    564   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
    565     return false;
    566 
    567   // If the extension uses spanning incognito mode, make sure we're always
    568   // using the original profile since that is what the extension process
    569   // will use.
    570   if (!IncognitoInfo::IsSplitMode(extension))
    571     profile = profile->GetOriginalProfile();
    572 
    573   if (!lazy_background_task_queue_->ShouldEnqueueTask(profile, extension))
    574     return false;
    575 
    576   pending_channels_[GET_CHANNEL_ID(params->receiver_port_id)] =
    577       PendingChannel(profile, extension->id());
    578   scoped_ptr<OpenChannelParams> scoped_params(params);
    579   lazy_background_task_queue_->AddPendingTask(profile, extension->id(),
    580       base::Bind(&MessageService::PendingOpenChannel,
    581                  weak_factory_.GetWeakPtr(), base::Passed(&scoped_params),
    582                  params->source->GetID()));
    583   return true;
    584 }
    585 
    586 void MessageService::PendingOpenChannel(scoped_ptr<OpenChannelParams> params,
    587                                         int source_process_id,
    588                                         ExtensionHost* host) {
    589   if (!host)
    590     return;  // TODO(mpcomplete): notify source of disconnect?
    591 
    592   // Re-lookup the source process since it may no longer be valid.
    593   content::RenderProcessHost* source =
    594       content::RenderProcessHost::FromID(source_process_id);
    595   if (!source)
    596     return;
    597 
    598   params->source = source;
    599   params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
    600                                                   MSG_ROUTING_CONTROL,
    601                                                   params->target_extension_id));
    602   OpenChannelImpl(params.Pass());
    603 }
    604 
    605 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
    606                                           int port_id,
    607                                           const std::string& error_message) {
    608   ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
    609   port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
    610 }
    611 
    612 }  // namespace extensions
    613